问题
I'm trying to create a simple generic find function in TypeScript, along the lines of:
export function findFirst<T, U>(
array: T[],
predicate: (item: T) => boolean,
selector?: (item: T) => U): U {
...
}
So, my parameters are:
- the array to filter through
- a predicate to test each element
- a selector to get the return value
What I want to do is provide a default selector, i.e. if no selector is provided, just return the whole value, i.e. something like:
if (typeof selector === "undefined")
selector = (x) => x;
However this, (or even (x) => <U>x
) breaks the generic definition of the function. How can I achieve a default selector without removing the generic parameters?
If I use code like:
var arr = [1,2,3,4];
var even = findFirst(arr, x => x % 2 === 0);
i.e. return the first even number, it infers the type of y as {}
i.e. object
instead of number.
It seems that, as U can only be inferred from the selector
parameter, which is undefined in this case, U defaults to object
.
I know I ask a bit too much of the type inference, but is there any way around this?
回答1:
Here is the complete code:
export function findFirst<T, U>(
array: T[],
predicate: (item: T) => boolean,
selector: (item: T) => U = (x:T)=> <U><any>x): U {
return array.filter(predicate).map(selector)[0];
}
Reason for <U><any>
: Type T
can be asserted to type U
only if T is a subtype of U OR U is a subtype of T. Since that is not determinable you need to convert to <any>
before you can assert to <U>
回答2:
Since a U
isn't necessarily a T
, you'd need to change the type assertion to be less specific by using any
:
selector = x => <any>x;
回答3:
You can just move the default value to the parameter declaration.
function findFirst<T, U>(
array: T[],
predicate: (item: T) => boolean,
selector: (item: T) => U = (x => x)): U {
// ....
}
来源:https://stackoverflow.com/questions/28299380/generic-casting-in-typescript