Reputation: 28790
Say I have this type:
export type Transformer = <T extends any[], U>(
data: T,
) => U;
THen I have this function which I want to conform to this type:
export const transform: Transformer = (
data: Result[]
): { data:Result[] } => {
if (!data) {
return { data: [] };
}
data.forEach((record:Result) => {
record.extraStuff = {
foo: 'bar'
};
});
return { data: data };
};
The compiler complains with:
Type '(data: Result[]) => { data: RecordMatchingSearchResult[]; }' is not assignable to type 'Transformer'.
Type '{ data: Result[]; }' is not assignable to type 'U'.
Do I need to add a generic constraint to U to make it inferred.
I also did not write the type but it seems a bit weird that it does not accept generic arguments but they exist on the function instead.
Upvotes: 1
Views: 70
Reputation: 249646
The problem with your function is that it is not really generic. You have a generic function signature ( Transformer
) and you try to assign a function that is not generic at all.
The problem occurs with the return type specifically because the return type must be specified by the caller, so the caller will expect the return type it specified not your non generic result ( { data: Result[] }
). If your assignment was allowed this call would cause a runtime error:
let result = transform<Result[], { other: number }>([]);
result.other // this would cause an error
If the type of the result is fixed you should just declare it, and the function implementation itself should be generic:
export type Transformer = <T extends { extraStuff: any }>(
data: T[],
) => { data: T[] };
class Result {
extraStuff: any;
}
export const transform: Transformer = <T extends { extraStuff: any }>(data: T[]): { data: T[] } => {
if (!data) {
return { data: [] };
}
data.forEach((record: T) => {
record.extraStuff = {
foo: 'bar'
};
});
return { data: data };
};
Or you could move the generics of the Transfomer
from the function signature to the type, and specify the type arguments when you declare the transform
function and so the functions itself would not have to be generic:
export type Transformer<T extends { extraStuff: any }, U> = (
data: T[],
) => U;
export const transform: Transformer<Result, { data: Result[] }> = (data: Result[]): { data: Result[] } => {
if (!data) {
return { data: [] };
}
data.forEach((record: T) => {
record.extraStuff = {
foo: 'bar'
};
});
return { data: data };
};
Upvotes: 3