Home > Enterprise >  Infer to a narrow string literal type from return type
Infer to a narrow string literal type from return type

Time:12-29

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?

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

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[] | [], 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].

  • Related