gus3001
gus3001

Reputation: 919

How do you constrain a Generic type in a Typescript Function Interface?

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 myFun3so we make sure they conform to SomeFunction?

Upvotes: 1

Views: 1989

Answers (1)

bugs
bugs

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

Related Questions