Reputation: 7232
This is a simplified example:
function doSomething(animal: 'bird' | 'fish'){ }
let flies=true;
const animal = flies ? 'bird' : 'fish'
doSomething(animal);
Typescropt infers type 'bird' | 'fish' in the assignation to animal from the ternary conditional. (if animal weren't const it would complain as it would infer type string not being assignable to 'bird' | 'fish')
But
const parms ={
animal: flies ? 'bird' : 'fish'
}
doSomething(parms); /* Argument of type '{ animal: string; }' is not
assignable to parameter of type '{ animal: "bird" | "fish"; } */
Here it's infering string from the ternary conditional. Is there a way to keep things in this style (ie. not having to define a type and declaring the field animal as that type)
Upvotes: 2
Views: 1000
Reputation: 250416
Typescript only infers string literal types in certain situation. A property is unusually not one of those cases unless there are extra circumstances to hint a literal type for the property. (it has nothing to do with the ternary operator).
In Typescript 3.4 (unreleased at the time of writing, but already available as typescript@next
in npm
) you will be able to hint the compiler that you want object literals inferred as per this issue:
let flies=true;
//types as { readonly animal: "bird" | "fish"; }
const parms ={
animal: flies ? 'bird' : 'fish'
} as const
In 3.3 and below you could use a function to tell the compiler you want a literal type inferred:
let flies=true;
function withLiteralTypes<T extends Record<string, P>, P extends string | number | null | boolean | Record<string, P>> (o: T) {
return o;
}
// types as { animal: "bird" | "fish"; }
const parms =withLiteralTypes({
animal: flies ? 'bird' : 'fish',
})
Upvotes: 4