简体   繁体   中英

typescript infer string literal from ternary conditional

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)

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',
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM