从泛型类型推断通用参数

时间:2017-09-18 04:05:36

标签: typescript

在尝试推断特定对象的泛型类型的泛型参数时,我遇到了一个问题:

type Box<T extends object> = {
    value: T;
}

function set<T extends object>(box: Box<T>, newValue: T): void {
    box.value = newValue;
}

const bbox: Box<{ foo: string }> = { value: { foo: "bar" } };

set(bbox, { foo: "baz" }); // OK as expected
set(bbox, 42);             // ERR as expected
set(bbox, { bar: "baz" }); // ERR as expected

set(bbox, {}); // OK, unexpected
set(bbox, { /* no autocomplete/intellisense is given here for valid props */ });

如果您提供{}作为参数,则Typescript会将{}推断为该函数的有效类型。这也意味着在编辑器中,没有为指定对象类型的字段指定自动完成,因为{}匹配所有对象。

是否有关于Typescript如何推断通用参数的命令(即newValue的推理会覆盖Box<T>的推理,并且任何对象都可以分配给{})?如果是这样,有没有办法避免这种情况?

更新

您可以通过添加额外参数来部分解决此问题:

function set<T, TN extends T>(box: Box<T>, newValue: TN): T {
    box.value = newValue;
    return newValue;
}

const bbox: Box<{ foo: string }> = { value: { foo: "bar" } };

set(bbox, { }); // ERR, expected
set(bbox, { /* still no autocomplete/intellisense */ });

但是,您仍然没有收到任何自动填充/智能感知。我猜这是因为extends,以及你不再直接寻找T

2 个答案:

答案 0 :(得分:2)

我不太清楚自动完成的工作原理如何告诉您为什么它不适用于您的情况;我的直觉是它还没有完全致力于泛型类推理。强制它提交推断类型的一种解决方法是将set更改为curried function,如下所示:

const intelliSet = <B extends Box<{}>>(box: B) => 
  (newValue: B['value']) => set(box, newValue);

intelliSet(bbox)( { foo: 'bar' }); // note the second function call
intelliSet(bbox)( { /* autocomplete works here */ });

我不知道是否有非解决方案。如果一个人不存在,我倾向于在GitHub上提出建议问题。 This one可能具有相关性,尤其是this comment。祝你好运!

答案 1 :(得分:1)

如果您声明set,可以让TypeScript从第一个参数开始进行推理:

function set<T extends object, B extends Box<T>>(box: B, newValue: B['value']): void {
    box.value = newValue;
}

不知道它是否修复了自动完成问题。