David Gomes
David Gomes

Reputation: 5845

Let TypeScript infer (some or all) generic parameter

Let's say I have a generic type Gen<T>:

type Gen<T> = {
    t: T,
    x: boolean,
};

And then I have some function that takes in a Gen but does not care about the T type:

function handleGen1(gen) {
    if (gen.x) {
        return gen;
    }
}

How would I type handleGen1? Currently I can only see this way:

function handleGen1<T>(gen: Gen<T>) {
    if (gen.x) {
        return gen;
    }
}

Is there a cleaner way, like in Flow (function handleGen1(gen: Gen<*>) { ... })?

Also, what if my function depends only on some of the type arguments?

type Gen<P, E> = {
  p: P,
  e: E,
  x: boolean,
}

function handleGen2(gen) {
    if (gen.x) {
        return gen.p;
    }
}

I would like to type that as:

handleGen2: (gen: Gen<P, *>) => P;

Upvotes: 2

Views: 1455

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250336

There is no equivalent to the * syntax in typescript. The option you found with declaring the type parameter is a good one. Note that at call site the extra parameter does not have to be specified, typescript will infer the apropriate T

type Gen<T> = {
    t: T,
    x: boolean,
};

function handleGen1<T>(gen: Gen<T>) {
    if (gen.x) {
        return gen;
    }
}

handleGen1({
    t: 1,
    x: true
}) // T infered as number

If you have more parameters to Gen you will to declare one for each type parameter:

type Gen<T, P> = {
    t: T,
    p: P,
    x: boolean,
};

function handleGen1<T, P>(gen: Gen<T, P>) {
    if (gen.x) {
        return gen;
    }
}

handleGen1({
    t: 1,
    p: "",
    x: true
}) // T inferred as number, P number

Now if you truly don't use the type parameter in any other position you can go with Gen<any> or Gen<unknown>. In your example, you do use T since the return type is going to be Gen<T> so Gen<any> will not forward the type parameter. If that were not the case we can use this option:

type Gen<T> = {
    t: T,
    x: boolean,
};

function handleGen1(gen: Gen<unknown>) {
    if (gen.x) {
        console.log(gen.t);
    }
}

handleGen1({
    t: 1,
    x: true
}) // works fine 1 is assignable to unknown 

A disadvantage of having to specify the type parameters is having to specify the type constraint as well.

Upvotes: 3

Related Questions