为什么 Partial 接受另一种类型的额外属性?

Dou*_*los 5 partial typescript

给定接口 A 和 B,它们包含一个x1共同的属性

interface A {
  a1: number;
  a2: number;
  x1: number;  // <<<<
}

interface B{
  b1: number;
  x1: number;  // <<<<
}
Run Code Online (Sandbox Code Playgroud)

并给出了实现ab

let a: A = {a1: 1, a2: 1, x1: 1};
let b: B = {b1: 1, x1: 1};
Run Code Online (Sandbox Code Playgroud)

这只是通过,即使b1不属于Partial<A>

let partialA: Partial<A> = b;
Run Code Online (Sandbox Code Playgroud)

但这失败了,因为b1不属于Partial<A>

let partialA: Partial<A> = {b1: 1, x1: 1};
Run Code Online (Sandbox Code Playgroud)

有人可以告诉我为什么吗?

Tit*_*mir 7

这将是一段旅程,所以请和我一起坚持下去:

通常,子类型应该可分配给基类型。在 Typescript 中,具有更多属性的类型应该可以分配给仅具有属性子集的类型。例如,这是合法的:

let source = { a1: 0, a2: 0}
let target: { a1: number } = source
Run Code Online (Sandbox Code Playgroud)

现在令人惊讶的是,由于结构类型的工作方式Partial<A>是 的子类型Partial<B>并且Partial<B>是 的子类型Partial<A>。子类型中可能会缺少可选属性,因此类型中缺少可选属性不会取消该类型作为子类型的资格。如果我们删除可选属性,我们只留下{}它可以是任何其他类型的基本类型。如果我们要求编译器使用条件类型回答这个子类型问题,编译器在这一点上同意我的观点:

type q1 = Partial<A> extends Partial<B> ? "Y" : "N" // Y
type q2  = Partial<B> extends Partial<A> ? "Y" : "N" // Y
Run Code Online (Sandbox Code Playgroud)

对此有一个例外(好吧,也许有两个),将对象文字直接分配给特定类型的引用。这称为多余的属性检查,因为如果我们直接执行上述赋值,我们会得到一个错误:

let target: { a1: number } = { a1: 0, a2: 0} // err  
Run Code Online (Sandbox Code Playgroud)

这是一个错误的原因是错误地创建具有更多属性或拼写错误的属性的对象文字是一个常见错误,并且此检查(这违反了子类型应可分配给基类型的原则)是在那里发现这个错误。这也是您收到错误的原因

let partialA: Partial<A> = {b1: 1, x1: 1};
Run Code Online (Sandbox Code Playgroud)

但多余的属性检查仅在将对象文字直接分配给特定类型的变量时才会启动。因此,在分配时,let partialA: Partial<A> = b;它不会触发过多属性检查的错误。

另一个复杂之处是Partial<A>所谓的弱类型。从引入此类类型检查的PR中:

弱类型是一种仅具有可选属性且不为空的类型。由于这些类型可以从除具有匹配的不可分配属性的类型之外的任何类型进行分配,因此它们的类型检查非常弱。这里的简单修复是要求类型只能分配给弱类型(如果它们不完全不相交)。

现在,由于弱类型没有强制属性,因此遵循子类型应可分配给基类型的原则,任何其他对象都可分配给此类类型:

let k = { foo: 0 }
let partialA: Partial<A> = k;
Run Code Online (Sandbox Code Playgroud)

的类型k是 的子类型Partial<A>,当然k与 没有任何共同点Partial<A>,但这不是问题。毕竟Partial<A>不需要任何属性,所以不需要k任何属性,并且它有一个额外的属性,这通常是子类型所做的,通过添加成员变得更加具体。

上面的代码之所以是错误,是因为上面的 PR 引用假设将完全不相关的类型分配给弱类型可能是错误的。因此,就像多余的属性检查一样,引入了一条规则(该规则再次打破了子类型可分配给基类型的想法),该规则不允许进行此类分配。

然而,在您的情况下Partial<A>, 和Partial<B>确实有一些共同点x1,因此该规则不会捕获可能错误的分配。尽管令人惊讶,因为 和Partial<A>Partial<B>没有强制属性,但它们是彼此的子类型,除非有特定原因(例如过多的属性检查或这种额外的弱类型检测规则),否则允许分配。

  • 是否有“Partial”的替代方案来接受**仅来自另一种类型的字段而不接受其他任何内容(尽管不需要所有字段)?** (2认同)