简体   繁体   English

Typescript object 字面交集

[英]Typescript object literal intersection

say we have the following code:假设我们有以下代码:

type neverHanppens = string & object // never

type A = {
    name:'A'
}

type B = {
    nickName:'B'
}

const a:A = {
    name:'A',
    nickName:'B' // error:'nickName' does not exist in type 'A'.
}

const c:A & B = {
    name:"A",
    nickName:"B"
}

I think in typescript, A & B means a type is A and also is B at the same time, is there a type that is both a string and a object?我认为在 typescript 中, A & B表示一个类型是A ,同时也是B ,是否存在一个既是字符串又是 object 的类型? no, so string & object equals never , that make sense to me.不,所以string & object等于never ,这对我来说很有意义。

but how about the literal object intersection above?但是上面的文字 object 交点怎么样? as you can see, type A and B have not any property name in common, so it should be never .如您所见,类型AB没有任何共同的属性名称,所以它应该是never but why type A & B covers both property name and nickName ?但为什么类型A & B涵盖属性namenickName and you can see the variable a we defined that way we would got a error, so {name:'A', nickName:'B'} is not a type A , so it against the logical ( are both type ) above.你可以看到我们定义的变量a我们会得到一个错误,所以{name:'A', nickName:'B'}不是类型A ,所以它与上面的逻辑(都是类型)相反。

if we conclude that A & B means a type will cover A and B, then string & object shouldn't be never , it should means type string and type object.如果我们断定A & B意味着一个类型将覆盖 A 和 B,那么string & object不应该是never ,它应该意味着 type string 和 type object。

could someone explain what's wrong with my logic?有人可以解释我的逻辑有什么问题吗?

Object types represent the minimal requirements for an object. Object 类型代表 object 的最低要求。 So type A means any object that has a name property.所以类型A表示任何具有name属性的 object。 The type does not forbid any other properties from being present though.但是,该类型并不禁止存在任何其他属性。


type A = {
    name:'A'
}

const anonymous = {
    name:'A',
    nickName:'B'
} as const

const a: A =  anonymous //ok

Playground Link 游乐场链接

Generally a type that has extra properties, will be a subtype of the original type and thus will be assignable to the original type通常,具有额外属性的类型将是原始类型的子类型,因此可以分配给原始类型

The error you are getting when you assign an object with more properties to the variable typed as A is called excess property checks, and is actually a useful if confusing exception to the rule I stated above.当您将具有更多属性的 object 分配给类型为A的变量时,您遇到的错误称为过度属性检查,如果混淆了我上面提到的规则,它实际上是一个有用的例外。 Useful, because if you are assigning a fresh object literal to a variable or parameter with a specific type, you probably don't want extra properties, but confusing because it gives the impression object types are a complete description of the object that may be assigned to the object type (which as we say above it is not)很有用,因为如果您将新的 object 文字分配给具有特定类型的变量或参数,您可能不需要额外的属性,但令人困惑,因为它给人的印象是 object 类型是 ZA8CFDE6331BD59EB66AC96F8911C4 的完整描述到 object 类型(正如我们上面所说的,它不是)

So given this understanding, A & B now makes more sense.因此,鉴于这种理解, A & B现在更有意义。 The intersection of a type that must have name (but may have any other properties including nickname ) and a type that must have nickname (but may have any other properties including name ) is a type that must have name and nickname (but may have any other properties)必须具有name (但可能具有任何其他属性,包括nickname )的类型与必须具有nickname (但可能具有任何其他属性,包括name )的类型的交集是必须具有namenickname的类型(但可能具有任何其他属性)

Object types in TypeScript are open or extendible , not closed or exact (as requested in ms/TS#12936 ). TypeScript 中的 Object 类型是开放的或可扩展的,不是封闭的或精确的(如ms/TS#12936中所要求的)。 Object types only specify which properties should be present , they do not enforce that unmentioned properties are absent . Object 类型仅指定应该存在哪些属性,它们并不强制不存在未提及的属性。 So a type like所以像这样的类型

type A = {
    name: 'A'
}

just implies that an A has to have a name property whose type is "A" .只是意味着A必须具有name类型为"A"的属性。 It does not imply that an A has only a name property.并不意味着A只有一个name属性。 Object types are extendible and you can always add properties to them without breaking them: Object 类型是可扩展的,您始终可以向它们添加属性而不会破坏它们:

interface AlsoA extends A {
    nickName: string;
}
const alsoA: AlsoA = {
    name: 'A',
    nickName: 'B'
}
const stillA: A = alsoA; // okay

The confusion you are having stems from the fact that object literals undergo excess property checking , resulting in the warning you saw when you directly assign an object literal with an extra property to a variable whose type doesn't know about it:您遇到的困惑源于这样一个事实,即object 文字经历了过多的属性检查,导致您在直接将具有额外属性的 object 文字分配给类型不知道的变量时看到警告:

const a: A = {
    name: 'A',
    nickName: 'B' // error:  Object literal may only specify known properties
}

The problem isn't that {name: "A", nickName: "B"} isn't a valid A (despite what the error might say).问题不在于{name: "A", nickName: "B"}不是有效A (尽管错误可能会说什么)。 It is a valid A .一个有效A The problem is that the object literal {name: "A", nickName: "B"} is immediately assigned to a variable of type A which has no knowledge of nickName .问题是 object 文字{name: "A", nickName: "B"}立即分配给不知道nickNameA类型变量。 The bug being caught here is that someone is probably accidentally throwing away information.这里发现的错误是有人可能不小心丢弃了信息。 It's not a type safety issue;这不是类型安全问题; it's more of a linter warning.这更像是一个短绒警告。


Now that we know that object types are open and extendible, then the intersection type A & B should be both an A and a B , which means it must have a name property whose type is "A" and a nickName property whose type is "B" .既然我们知道 object 类型是开放和可扩展的,那么交集类型A & B应该既是AB ,这意味着它必须具有类型为"A"name属性和类型为"B"nickName属性"B" This is not equivalent to never , as A does not imply the absence of a nickName property, and B does not imply the absences of a name property.这不等同于never ,因为A并不意味着不存在nickName属性,而B也不意味着不存在name属性。

Playground link to code Playground 代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM