Home > Blockchain >  Utility type to retrieve an array as union
Utility type to retrieve an array as union

Time:01-06

I want to type the returnvalue as a union of elements of an array, that is being passed as an argument.

For example, this function returns one of the elements of the array:

type GetValue = <T extends string[]>(values: T, predicate: (v) => boolean) => HOWTOTYPETHIS

This function is being used as:

const foundValue = getValue(['a', 'b', 'c'], x => x ==='a')
// type of foundValue must be `'a' | 'b' | 'c'`

CodePudding user response:

You can retrieve the values of T extends string[] by using T[number]

Furthermore you can make them final by using readonly keyword. This is similar to using as const.

The type becomes

type GetValue = <T extends readonly string[]>(values: T, predicate: (v) => boolean) T[number]

Unfortunately, you need to type the array that you pass using as const. It's not inferred as being a final.

const foundValue = getValue(['a', 'b', 'c'] as const, x => x ==='a')
// foundValue: 'a' | 'b' | 'c'

Here is a playground link

CodePudding user response:

To remove the need for as const in your solution, use variadic tuples:

type GetValue = <T extends readonly string[]>(values: [...T], predicate: (v: T[number]) => boolean) => T[number]
//                                                    ^^^^^^

Arguments will now be inferred literally without requiring as const.

Playground

CodePudding user response:

To get a union of the types of the values of a tuple or array type, you use ArrayType[number].
For example:

type MyArray = string[]
type t1 = MyArray[number]
//   ^? string

type MyTuple = [number, string]
type t2 = MyTuple[number]
//   ^? string | number

So for your case, you can use this:

type GetValue = <T extends string[]>(values: [...T], predicate: (v) => boolean) => T[number]

The return type is now T[number], which is the union you wanted.

The type for the parameter values uses a "variadic tuple type" to make TypeScript use the "actual" type of the argument, instead of the wider type string[].

If the predicate is being called with each element of the array, one by one, you can type its parameter in the same way: predicate: (v: T[number]) => boolean.

Playground link

Some references:

  • Related