Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript: Constrain function generic type based on the expected return type

I look to fix the typing of the addRandomValue function, so that the Typescript compiler doesn't allow the below call, because baz is not in FooBar.

type WithRandomNumber<T> = T & { randomValue: number; };

function addRandomValue<T>(inputObj: T): WithRandomNumber<T> {
    return {
        ...inputObj,
        randomValue: Math.random(),
    };
}

interface FooBar {
    foo: string;
    bar: number;
};

const resultObj: WithRandomNumber<FooBar> = addRandomValue({
    foo: 'hello',
    bar: 100,
    baz: true,
});

That is, I want to constrain the generic T of addRandomValue (and hence the type of inputObj), so that if the expected return type is WithRandomNumber<Foobar> (because that's the variable type that we assign the return value to), then T has to equal FooBar.

like image 603
bzyr Avatar asked Feb 02 '26 02:02

bzyr


1 Answers

You cannot force the compiler to balk at the assignment based on the LH type declaration, you instead must pass the generic argument when you call the function:

type WithRandomNumber<T> = T & { randomValue: number; };

function addRandomValue<T>(inputObj: T): WithRandomNumber<T> {
    return {
        ...inputObj,
        randomValue: Math.random(),
    };
}

interface FooBar {
    foo: string;
    bar: number;
};

const resultObj = addRandomValue<FooBar>({
    foo: 'hello',
    bar: 100,
    baz: true,
});

The problem isn't that the compiler isn't smart enough, it has to do with how Javascript is evaluated per the spec. Since you don't pass the generic argument at the call site it infers type {foo: string bar: number, baz: boolean } and evaluates the RH expression then it assigns the result to the LH var with the type you've declared. Because TS is structurally-typed that is indeed a valid assignment since it has all of the properties required by FooBar:

const foo = {
    foo: 'hello',
    bar: 100,
    baz: true,
};

const bar: FooBar = foo;

Playground

like image 56
Jared Smith Avatar answered Feb 04 '26 01:02

Jared Smith



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!