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
.
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
.
Some references: