Consider:
type Foo = {
bar: string,
baz: number
}
const bars = ['a', 'b', 'c'];
const foos = bars.map<Foo>((bar, i) => {
return {
bar,
baz: i
}
});
This this will not enforce the exact type of the return value from the map, e.g. I can say
return {
bar,
baz: i,
extraProp: 'boo!' // this works! (bad - i want this to fail)
}
and it will work fine. This works the same as if I didn't use a generic type and used a type assertion on the return value:
return {
bar,
baz: i,
extraProp: 'boo!' // works (bad)
} as Foo
The only way I can figure out to get the actual type to be enforced completely is creating a temporary variable:
const returnVal: Foo = {
bar,
baz: i,
// extraProp: 'boo!' // won't work - good! typescript prevented a bug!
}
return returnVal;
Is there any syntax that permits creating an anonymous object such as in the return
statement that would allow enforcement of the type completely, rather than just a type assertion?
Yes, you should make it a habit to explicitly set all types, it's will prevent having unexpected values and also good for readability.
What does ?: mean in TypeScript? Using a question mark followed by a colon ( ?: ) means a property is optional. That said, a property can either have a value based on the type defined or its value can be undefined .
The anonymous type declaration starts with the new keyword. The declaration initializes a new type that uses only two properties from Product . Using anonymous types causes a smaller amount of data to be returned in the query.
Inside the function we assign the parameters to properties in the object. To do this, we have to specify the this keyword, which refers to the calling object. The variables and parameters may have the same names. Anything we pass to the constructor as an argument, will be assigned to the property of the object.
The problem is that object literals are checked for extra properties only when they are directly assigned to a parameter/variable/return value. While you do specify the type parameter on map
the arrow function will first be typed first with this signature:
(bar: string , i: number) => {
bar: string,
baz: number,
extraProp: string
}
And then this function is checked for compatibility with the argument of map (typed as (bar: string , i: number) => Foo
) and will be found to be compatible.
A simple work around would be to specify the type not on map
but the return type of the arrow function :
const foos = bars.map((bar, i): Foo => {
return {
bar,
baz: i,
extra: "" // error here, as expected
}
});
This is not a type assertion, but you do need to specify the type, but you do so on map
anyway, so the amount of typing is about the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With