Reputation: 919
Let's consider we have the following interfaces:
interface SomeInterface {a: string; b: number}
interface SomeFunction<T> {(arg: T) :T}
We can use the function interface like so:
const myFun: SomeFunction<string> = arg => arg;
but the issue with that is we specify the generic type T
as string, so it is no longer generic.
I would like to keep the type T
generic but also constrain it.
Declaring SomeFunction
like:
interface SomeFunction {<T>(arg: T) : T}
allows it to be used generically like:
const myFun: SomeFunction = (arg) => arg;
but then we lose the chance to constrain T
at the function declaration.
I would like my function that implements SomeFunction
to define that T
must extend SomeInterface
and I would like another function that also implements SomeFunction
to define that T
extends something else.
So, basically, I want something like this:
function myFun2<T extends SomeInterface>(arg: T): T {
console.log(arg.a);
return arg;
}
function myFun3<T extends {c: string }>(arg: T): T {
console.log(arg.c);
return arg;
}
The issue I have with the solution above is that there is no mention of the SomeFunction
interface in these declarations even though we basically match it.
Is there a better way to declare myFun2
and myFun3
so we make sure they conform to SomeFunction
?
Upvotes: 1
Views: 1989
Reputation: 15323
If you want the ability to define constraints at call site, you can generalise SomeFunction
with a constraint type, like
interface SomeFunction<C> {
<T extends C>(arg: T) : T
}
and provide the correct constraint when defining your functions
const myFun2: SomeFunction<SomeInterface> = arg => {
console.log(arg.a) // ok
return arg
}
const myFun3: SomeFunction<{ c: string }> = arg => {
console.log(arg.c) // ok
return arg
}
You could also give a default constraint of type unknown
if you wanted to allow unconstrained functions, like
interface SomeFunction<C = unknown> {
<T extends C>(arg: T): T
}
const unconstrained: SomeFunction = arg => arg
Upvotes: 3