Reputation: 55
Here's a small code example (side note: I'm running Typescript v3.8.3):
interface IOptions<T> {
arg: T;
}
interface IExtraOptions extends IOptions<number> {
arg2: string;
}
type Func = <T, OptionsT extends IOptions<T>>(options: OptionsT) => T;
const f: Func = (options: IExtraOptions): number => {
return options.arg2 === 'dev' ? 0 : options.arg;
};
I would expect this to work, because IExtraOptions
extends IOptions
and would thus satisfy the OptionsT extends IOptions<T>
constraint, but I get:
Type 'OptionsT' is not assignable to type 'IExtraOptions'.
Property 'arg2' is missing in type 'IOptions' but required in type 'IExtraOptions'.ts(2322)
Removing the OptionsT
argument altogether and just using IOptions<T>
as the type argument for "options" gives the same error. Replacing "number" with a non-default type doesn't fix it either. Anyone know what I'm doing wrong?
Upvotes: 1
Views: 786
Reputation: 250156
If you have a generic function, the generics type parameters of the function are for the caller to determine, not for the implementation to fix as some arbitrary types. For example given your example, this call would be valid f<boolean, IOptions<boolean>>({ arg: true })
and the implementation you specified does not return an object to satisfy those type parameters.
The conclusion is that if you have a generic function, generally nothing but a generic function will satisfy as the implementation (although using very loose types such as any
, never
or unknown
might also work).
If you want to create specialized functions, don't use a generic function, use a generic type that happens to be a function:
type Func <T, OptionsT extends IOptions<T>> =(options: OptionsT) => T;
const f: Func<number, IExtraOptions> = (options ) => {
return options.arg2 === 'dev' ? 0 : options.arg;
};
Also you can derive T
from TOptions
to simplify things a bit:
type Func <OptionsT extends IOptions<any>> =(options: OptionsT) => OptionsT['arg'];
const f: Func<IExtraOptions> = (options ) => {
return options.arg2 === 'dev' ? 0 : options.arg;
};
Upvotes: 1