简体   繁体   中英

Infer to a narrow string literal type from return type

const createFruit = <T extends string[]>(fruits: T): typeof fruits[0] => fruits[0]

const fruit = createFruit(['apple', 'orange']) // fruit is of type `string`

I want the type of fruit to be inferred to the string literal apple . Is there no way to do this?

Using the variadic tuple syntax for the fruits parameter will hint to the compiler to infer the literal type.

const createFruit = <T extends string[]>(
  fruits: [...T]
): typeof fruits[0] => fruits[0]

const fruit = createFruit(['apple', 'orange'])
//    ^? fruit: "apple"

Playground

From TS 5.0 you will be able to use the const modifier on type parameters like this:

const createFruit = <const T extends readonly string[]>(fruits: T): T[0] => fruits[0]

const fruit = createFruit(['apple', 'orange']) 

For now a possible solution is the following:

const createFruit = <N extends string, T extends N[] | []>(fruits: T): T[0] => fruits[0]

const fruit = createFruit(['apple', 'orange']) 

In which you declare another type parameter N to narrow the inference from strings to actual string type literals, then you set the upper-bound for T to T[] | [] T[] | [] , where the | [] | [] tells TS to infer a tuple type instead of an array tipe.

In both cases the return type could simply be T[0] .

In order to get stronger typings that would give the desired behavior, just type the argument as immutable array, and then use the const assertion to type the value you pass as argument:

const createFruit = <T extends readonly string[]>(fruits: T): typeof fruits[0] => fruits[0]

const fruit = createFruit(['apple', 'orange'] as const) // fruit is of type `apple`

TypeScript playground

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