TypeScript接口功能字段矛盾类型错误

问题描述

我具有以下类型,该类型确定所有属性都将是函数,不接受任何参数,也不能接受类型为Record<string,any>的单个参数:

type FnTrait = Record<
  string,(input?: Record<string,any>) => any
>;

我尝试将此类型扩展到另一个接口(我希望具有相同的约束)。

interface HasFn extends FnTrait {
  someFn(): string; // no problem
  anotherFn(o: {id: string}): number; // ts error 2411
}

这会在anotherFn上产生错误:Property 'anotherFn' of type '(o: { id: string; }) => number' is not assignable to string index type '(input?: Record<string | number | symbol,any> | undefined) => any'.

为什么someFn没有产生错误,而anotherFn却产生了错误2411?似乎应该允许缩小范围。

任何帮助将不胜感激。谢谢!

解决方法

这是function types being contravariant in their parameters的实例。单词“相反”的意思是“以相反的方式变化”。如果使函数的参数更特定于 (窄),则使函数类型本身更加 general (宽)。这意味着您不是将options: { animation: { duration: 2000 },... 设为HasFn子类型(这就是FnTrait的意思),而是使它成为超类型。这是不允许的,并且违反了substitutability的原则。

尤其是, extends是错误的,因为它要求其参数具有anotherFn()值的string属性,而id没有。期望您可以不带参数,也可以具有几乎任何类型的单个参数来调用FnTrait["anotherFn"]的任何属性。但是,如果调用FnTrait的{​​{1}}方法不带参数,或者参数缺少正确的HasFn属性,则anotherFn()可能会爆炸。因此,根据定义,id不可分配给HasFn,尽管已声明对其进行了扩展:

FnTrait

由于const hasFn: HasFn = { someFn: () => "",anotherFn: o => o.id.length } const fnTrait: FnTrait = hasFn; fnTrait.anotherFn({ a: 123 }); // okay at compile time,explodes at runtime 意味着您无法安全地替换请求值anotherFn()的{​​{1}}值,因此FnTrait无法分配给HasFn,你会得到一个错误。


FnTrait不是 错误的原因是因为a function of fewer parameters is assignable to a function that takes more parameters。这是因为HasFn将根据需要忽略传递给它的任何参数,因此将其视为可能会接收参数的函数是安全的:

someFn()

这与someFn()失败的原因相同:可替代性。

Playground link to code

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...