有人可以解释为什么这不起作用吗?

dan*_*aze 6 typescript

这个想法是强制不使用传递给函数的对象中的某些字段,并且您可以使用其他任何内容(这就是为什么extends

type ForbiddenFields = 'a' | 'b' | 'c';
type Data = { [K in ForbiddenFields]?: never };

function foobar<T extends Data>(data: T): void {
  //...
}

const obj = { x: 1, y: 2 };
foobar(obj); // Type '{ x: 1, y: 2 }' has no properties in common with type Data
Run Code Online (Sandbox Code Playgroud)

为什么我得到

类型 '{ x: 1, y: 2 }' 与 Data 类型没有共同的属性

如果函数只是期望一个扩展的 Data对象,那么这不是等于说<T extends {}>但只是强制执行如果ForbiddenField指定了 a 则它必须存在never- 因此,不能存在吗?

jca*_*alz 2

这与TypeScript 2.4 中引入的弱类型检测发生冲突。由于Data的属性都是可选 ,因此编译器将其视为“弱类型”,因此与任何其他类型不兼容,除非至少有一个重叠属性。就像对象文字的多余属性检测一样,这并不是真正的类型系统健全性功能;它更像是一个 linter 规则,可以阻止它认为可能是错误的事情。

弱类型检测的发行说明说:

由于这是一个重大更改,您可能需要了解与严格对象文字检查相同的解决方法:

  • 如果属性确实存在,则声明它们。
  • 向弱类型添加索引签名(即[propName: string]: {})。
  • 使用类型断言(即opts as Options)。

我们可以使用第二个建议并添加字符串索引签名;因为我们不想限制任何其他属性,所以我们可能应该将值设置为类型any因为即使类型安全unknown最终也会排除没有索引签名的接口类型,这是我们不想做的)。它可能看起来像这样:

interface AnyData extends Data {
  [k: string]: any;
}

function foobar<T extends AnyData>(data: T): void {
  //...
}
Run Code Online (Sandbox Code Playgroud)

您可以验证事情是否按预期运行:

const obj = { x: 1, y: 2 };
foobar(obj); // okay

const obj2 = { x: 1, y: 2, c: 3 };
foobar(obj2); // error!  Types of property 'c' are incompatible.

interface Baz {
  x: 1,
  y: 2
}
declare const baz: Baz;
foobar(baz); // okay
Run Code Online (Sandbox Code Playgroud)

Playground 代码链接