为什么 Partial 接受另一种类型的额外属性? [英] Why Partial accepts extra properties from another type?

查看:83
本文介绍了为什么 Partial 接受另一种类型的额外属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Given interfaces A and B, which contain a x1 property in common

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

interface B{
  b1: number;
  x1: number;  // <<<<
}

并给出实现 ab

let a: A = {a1: 1, a2: 1, x1: 1};
let b: B = {b1: 1, x1: 1};

这只是通过了,即使 b1 不属于 Partial:

This simply passes, even though b1 does not belong to Partial<A>:

let partialA: Partial<A> = b;

但这失败了,因为 b1 不属于 Partial:

but this fails because b1 does not belong to Partial<A>:

let partialA: Partial<A> = {b1: 1, x1: 1};

谁能告诉我为什么?

推荐答案

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

This is going to be a bit of a journey so hang in there with me:

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

Generally a sub-type should be assignable to a base-type. In Typescript a type with more properties should be assignable to a where a type with just a subset of the properties is expected. So this for example is legal:

let source = { a1: 0, a2: 0}
let target: { a1: number } = source

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

Now surprisingly, because of the way structural typing works Partial<A> is a subtype of Partial<B> and Partial<B> is a subtype of Partial<A>. Optional properties can be missing in a subtype, so optional properties missing from a type do not disqualify a type from being a subtype. An if we remove the optional properties we are just left with {} which can be a the base type of any other type. The compiler agrees with me on this point if we ask it to answer this subtyping question using conditional types:

type q1 = Partial<A> extends Partial<B> ? "Y" : "N" // Y
type q2  = Partial<B> extends Partial<A> ? "Y" : "N" // Y

对此有一个例外(可能有两个),将对象文字直接分配给特定类型的引用.这被称为额外的属性检查,因为如果我们直接执行上面的赋值,我们会得到一个错误:

There is one exception to this (ok maybe two), assignment of object literals directly to a reference of a particular type. This is called excess property checks as is the reason that if we were to perform the above assignment directly we would get an error:

let target: { a1: number } = { a1: 0, a2: 0} // err  

这是一个错误的原因是错误地创建具有更多属性或拼写错误的属性和此检查的对象文字是一个常见错误(这违反了子类型应该可分配给基类的原则)type) 是否可以捕获此错误.这也是您在

The reason this is an error is that it is a common error to mistakenly create an object literal with more properties or misspelled properties and this check (which is a violation of the principle a sub-type should be assignable to a base-type) is there to catch this mistake. This is also the reason you are getting an error on

let partialA: Partial<A> = {b1: 1, x1: 1};

但多余的属性检查仅在将对象文字直接分配给特定类型的变量时起作用.所以在赋值 let partialA: Partial= b; 它不会触发过多的属性检查错误.

But excess property checks only kick in on direct assignment of an object literal to variable of a specific type. So on the assignment let partialA: Partial<A> = b; it will not trigger an error on excess property checks.

更复杂的一点是 Partial 是所谓的弱类型.从 PR 介绍对此类类型的检查:

One further complication is that Partial<A> is what is called a weak type. From the PR introducing checks for such type:

弱类型是只有可选属性且不为空的类型.因为除了具有匹配的不可赋值属性的类型之外,这些类型都可以从任何类型中赋值,所以它们的类型检查非常弱.这里的简单解决方法是要求一个类型只有在它们不完全不相交的情况下才能分配给弱类型.

A weak type is one which has only optional properties and is not empty. Because these types are assignable from anything except types with matching non-assignable properties, they are very weakly typechecked. The simple fix here is to require that a type is only assignable to a weak type if they are not completely disjoint.

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

Now since a weak type has no mandatory properties, following the principle a sub-type should be assignable to a base-type, any other object would be assignable to such a type:

let k = { foo: 0 }
let partialA: Partial<A> = k;

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

The type of k is a sub-type of Partial<A>, sure k has nothing in common with Partial<A> but that is not an issue. After all Partial<A> does not require any propertie, so k does not need any, and it has one extra property, which is generally what a sub-type does, become more specific by adding members.

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

The reason the code code above is an error is because of the PR are reference above which postulates that assigning a completely unrelated type to a weak type is probably an error. So like excess property checks a rule was introduced (a rule which again breaks the idea a subtype is assignable to a base type) that disallows such assignments.

在你的情况下,PartialPartial 确实有一些共同点 x1 所以这个规则没有抓住可能是错误的分配.虽然令人惊讶,因为 PartialPartial 都没有强制属性,但它们是彼此的子类型,除非有特定原因(例如多余的属性)检查或这个额外的弱类型检测规则)分配是允许的.

In your case however Partial<A> and Partial<B> do have something in common x1 so this rule does not catch the possibly mistaken assignment. Although surprising because both Partial<A> and Partial<B> have no mandatory properties, they are subtypes of one another and unless there is a specific reason (such as excess property checks or this extra weak type detection rule) the assignment is allowed.

这篇关于为什么 Partial 接受另一种类型的额外属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆