简体   繁体   English

Typescript - 基本接口和扩展接口的联合类型

[英]Typescript - Union Type of base interface and extended interface

I have the following code我有以下代码

interface BaseA {
  a: number;
}

interface SpecialA extends BaseA {
  b: number;
}

type A = BaseA | SpecialA

const a = {
    a: 5, b: 5
} as A

console.log(a.b)

I expected the code to be valid, but im getting the error我希望代码有效,但我收到错误

Property 'b' does not exist on type 'A'.
  Property 'b' does not exist on type 'BaseA'

It seems the type A is not what i was trying to define, i was expecting it to be equivelent to the following type似乎 A 类型不是我想要定义的,我期待它等同于以下类型

interface A {
  a: number;
  b?: number;
}

My questions are我的问题是

  1. why is the type A i defined different from the type A i expected to get?为什么我定义的 A 类型与我期望得到的 A 类型不同?
  2. how can i define the expected type A without defining it by hand?如何在不手动定义的情况下定义预期的 A 类型?

Note: i need to use the type SpecialA as is in some places, so not defining it and just defining expected A is not an option.注意:我需要在某些地方按原样使用 SpecialA 类型,因此不定义它而只定义预期的 A 不是一种选择。

Since A is a union, you need to narrow / discriminate your type to access non shared members.由于A是一个联合,您需要 缩小/ 区分您的类型以访问非共享成员。

interface BaseA {
  a: number;
}

interface SpecialA extends BaseA {
  b: number;
}

type A = BaseA | SpecialA

const a = {
  a: 5, b: 5
} as A

if ("b" in a) { // narrowing here
  console.log(a.b)
}

Playground 操场

By using as A , you've said "The variable a may contain a BaseA or a SpecialA ."通过使用as A ,您已经说过“变量a可能包含BaseASpecialA ”。 Later, you tried to use ab without any kind of type check, but since a may be just a BaseA (not a SpecialA ), that's a type error.后来,您尝试在没有任何类型检查的情况下使用ab ,但由于a可能只是一个BaseA (不是SpecialA ),这是一个类型错误。 TypeScript doesn't know that what a refers to has a b property; TypeScript 不知道a所指的内容具有b属性; it may be just a BaseA , which doesn't have b .它可能只是一个BaseA ,它没有b

You can resolve that by checking first:您可以通过首先检查来解决该问题:

if ("b" in a) {
    console.log(a.b);
}

Within the if block, TypeScript knows that a refers to SpecialA .if块中,TypeScript 知道a指的是SpecialA

Playground link 游乐场链接

You might be thinking: But a is a constant, not a variable.你可能会想:但是a是一个常数,而不是一个变量。 That's true, but the object the constant refers to can be modified to no longer have a b property:没错,但是常量引用的对象可以修改为不再具有b属性:

delete (a as any).b; // blech

If you're never going to remove the b property, either just use SpecialA as the type:如果您永远不会删除b属性,则只需使用SpecialA作为类型:

const a: SpecialA = {
    a: 5,
    b: 5,
};

Playground link 游乐场链接

...or use as const to tell TypeScript that the object will never be modified: ...或者使用as const告诉 TypeScript 该对象永远不会被修改:

const a = {
    a: 5,
    b: 5,
} as const;

Playground link 游乐场链接

Note that if you do the as const thing, there's no need for a type annotation on it at all.请注意,如果您执行as const操作,则根本不需要类型注释。 TypeScript's type checking is structural (based on the shape of things, what properties they have and their types), not nominal (based on the names of types). TypeScript 的类型检查是结构性的(基于事物的形状、它们具有的属性及其类型),而不是名义上的(基于类型的名称)。 But you could use the type A on it for some clarity for other programmers:但是您可以在其上使用类型A以使其他程序员更清楚:

const a: A = {
//     ^^^
    a: 5,
    b: 5,
} as const;

Playground link 游乐场链接

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

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