打字稿:基于预期的返回类型约束函数泛型类型

时间:2021-02-23 18:52:34

标签: typescript typescript-typings typescript-generics

我希望修复 addRandomValue 函数的类型,以便 Typescript 编译器不允许下面的调用,因为 baz 不在 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,
});

也就是说,我想约束 T 的泛型 addRandomValue(以及 inputObj 的类型),以便如果预期的返回类型是 WithRandomNumber<Foobar> (因为这是我们将返回值分配给的变量类型),那么 T 必须等于 FooBar

1 个答案:

答案 0 :(得分:1)

您不能强制编译器拒绝基于 LH 类型声明的赋值,而是必须在调用函数时传递泛型参数:

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,
});

问题不在于编译器不够智能,而是与根据规范评估 Javascript 的方式有关。由于您没有在调用站点传递泛型参数,它推断类型 {foo: string bar: number, baz: boolean } 并评估 RH 表达式 then 它将结果分配给具有您声明的类型的 LH var。因为 TS 是结构类型的,它确实是一个有效的赋值,因为它具有 FooBar 所需的所有属性:

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

const bar: FooBar = foo;

Playground