【问题标题】:Using Rest parameters syntax causes errors使用 Rest 参数语法会导致错误
【发布时间】:2021-04-28 02:06:27
【问题描述】:

这是我的设置:

定义属性

interface Props<T, X extends any[], Y extends any[]> {
  T?: T
  x?: <D extends T>(d: D, ...args: X) => number | Date | string
  y?: <D extends T>(d: D, ...args: Y) => number | Date | string
}

定义使用 Props 接口的组件

class Component<T, X extends any[], Y extends any[]> {
  _props: Props<T, X, Y>

  constructor(props:Props<T, X, Y>){
    this._props = props
  }
}

实例化组件(我希望组件从 props 中推断出泛型类型

const comp = new Component({
  T:{a:10, b:20},
  x:(d, g:number)=> d.a
})

我面临的问题是当我使用 x(或 y)属性时,将打印以下错误

Type '<D extends { a: number; b: number; }>(d: D, g: number) => number' is not assignable to type '<D extends { a: number; b: number; }>(d: D, g: number) => string | number | Date'.
  Types of parameters 'd' and 'd' are incompatible.
    Type 'D' is not assignable to type 'D'. Two different types with this name exist, but they are unrelated.
      'D' is assignable to the constraint of type 'D', but 'D' could be instantiated with a different subtype of constraint '{ a: number; b: number; }'.
        Type '{ a: number; b: number; }' is not assignable to type 'D'.
          '{ a: number; b: number; }' is assignable to the constraint of type 'D', but 'D' could be instantiated with a different subtype of constraint '{ a: number; b: number; }'.

这是Typescript Playground中的完整代码

我想要的是推断其余参数类型并在以后使用它,所以如果有人对如何克服这个问题有很大的帮助,请提供建议

【问题讨论】:

  • 嗯,你能解释一下为什么你需要使用通用的D 吗?你在这里所做的和只接受T 类型的参数的this code 有什么区别?如果这被证明是 TS 编译器中的错误或限制,则报告可能需要显示一个激发它的用例,而现在似乎没有理由让 xy 成为泛型方法
  • 无论如何,看起来this 可能是minimal reproducible example 的情况。我会看看我是否能找到关于这个的现有 GitHub 问题。
  • 我在 Svelte 框架中使用此代码,并且需要使用泛型 D 来正确推断类型,而没有 D 泛型我会得到任何类型,
  • 我对独立的用例更感兴趣。像&lt;T extends X&gt;(x: T)=&gt;void 这样的函数类型没有理由是泛型的,因为它可以替换为(x: X)=&gt;void。另一方面,像&lt;T extends X&gt;(x: T) =&gt; T&lt;T extends X&gt;(x: T, cb: (x: T)=&gt;void)=&gt;void 这样的函数类型或至少两次提到T 的函数类型不能用非泛型版本替换而不会丢失精度。如果我提出 GitHub 问题,我可能会做类似this 之类的事情
  • 这里的答案很可能是类型推断对你不起作用,你必须手动指定比你想要的更多的类型。

标签: typescript typescript-generics


【解决方案1】:

这是 TypeScript 编译器中的一个错误,应该(感谢这个问题)在下一个 TypeScript 版本中修复。


您看到的错误令人惊讶。从表面上看,函数类型&lt;D extends { a: number; b: number; }&gt;(d: D, g: number) =&gt; number 确实应该可以分配给&lt;D extends { a: number; b: number; }&gt;(d: D, g: number) =&gt; string | number | Date。编译器显然认为您提供的函数的推断类型中的D 类型参数可能无法分配给Component 构造函数所需的D 类型参数......但这不是很有意义,因为D 在这两种情况下都是参数而不是特定类型。经过一番研究,我在 TypeScript 的 GitHub 存储库中找不到现有的相关问题,所以我提交了microsoft/TypeScript#43833 询问发生了什么。

而且,正如我所提到的,显然它被认为是 TypeScript 编译器中的一个错误。此外,它已被修复;见microsoft/TypeScript#43835。所以好消息是它应该在 TypeScript 的下一个版本中得到修复。


在您可以使用固定版本之前,我发现保持函数通用的唯一解决方法是手动注释当前根据上下文推断的类型。这是多余的,但至少它有效。如果你不想写出类型{a: number, b: number},你可以这样做:

const t = { a: 10, b: 20 };
const comp = new Component({
  T: t,
  x: <D extends typeof t>(d: D, y: number) => d.a // no error now
});
/* const comp: Component<{
    a: number;
    b: number;
}, [y: number], any[]> */

在这里,我们让编译器将t 的类型推断为{a: number, b: number},然后在x 的注释中,我们在t 上使用typeof type query operator

希望这会让您度过难关,直到修复完成。 ?

Playground link to code

【讨论】:

    猜你喜欢
    • 2015-08-17
    • 1970-01-01
    • 2022-08-10
    • 1970-01-01
    • 2015-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-10
    相关资源
    最近更新 更多