网站搜索

当使用引用时,Typescript 的 Omit 不会显示错误


type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

interface objInterface {
  first: string;
  second: string;
}

const obj = {
  first: "first",
  second: "second"
};

const out: Omit<objInterface, "first"> = obj;

我本以为这会有一些智能感知错误,但实际上没有。然而,这个确实显示了一些错误,有人知道为什么吗?

const out: Omit<objInterface, "first"> = {
  first: 'first',
  second: 'second'
};

答案#1

除了@kingdaro关于对象字面量的多余属性检查的正确观点之外,

Omit<T,K> 的定义只是扩展了 T 的类型,使其不包含在 K 处的已知属性(“我不知道或者不关心 K 是否是一个属性;我会忽略它。”),这并不等同于在 K 处禁止一个属性。也就是说,T 是 Omit<T, K> 的子类型,任何 T 类型的值也可以赋值给 Omit<T, K> 类型。如果你的意图是实际上在 K 处禁止一个属性,你可以(某种程度上)通过指定 K 属性为可选且其值类型为 never(或 undefined,见下文)来实现。我们称之为 ForcefullyOmit<T, K>:

type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type ForcefullyOmit<T, K extends keyof T> = Omit<T, K> & Partial<Record<K, never>>; 

让我们看看它是否有效:

interface ObjInterface {
  first: string;
  second: string;
}

const obj = {
  first: "first",
  second: "second"
};

const out: ForcefullyOmit<ObjInterface, "first"> = obj; // error
// types of property "first" are incompatible
// string is not assignable to undefined

看起来不错。

这只是“某种程度上”禁止该键,因为它仍然允许该键的属性类型为 undefined(或 never),但这是 TypeScript 中的一种未解决的问题……语言并不总是区分缺失的属性和 undefined 的属性。

如果你的用例确实需要 ForcefullyOmit 的更严格行为,那就由你决定了。无论如何,希望这能帮到你;祝你好运!

答案#2

TypeScript 只有在将对象定义为字面量时才会对多余属性报错,这是设计使然。https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks