从泛型类型推断泛型参数

Inferring generic parameters from generic types

我 运行 在尝试推断特定对象的泛型类型上的泛型参数时遇到了问题:

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 */ });

但是,您仍然没有收到任何 autocomplete/IntelliSense。我猜这是因为 extends,以及您不再直接寻找 T 的原因。

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

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

不知道它是否解决了自动完成问题。

我对自动完成的工作原理知之甚少,无法确切地告诉您为什么它在您的情况下不起作用;我的直觉是它还没有完全致力于泛型类型推断。强制它提交推断类型的一种解决方法是将 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 is possibly relevant, especially this comment。无论如何,祝你好运!