TypeScript:具有可选值的歧视联合

Ben*_*ate 9 typescript

给出以下类型:

interface FullName {
  fullName?: string
}

interface Name {
  firstName: string
  lastName: string
}

type Person = FullName | Name;

const p1: Person = {};
const p2: Person = { fullName: 'test' };
const p3: Person = { firstName: 'test' }; // Does not throw
const p4: Person = { badProp: true }; // Does throw, as badProp is not on FullName | Name;
Run Code Online (Sandbox Code Playgroud)

我希望p3会导致编译器错误,但firstName没有lastName,但它没有 - 这是一个错误或预期?

此外,使FullName.fullName必需会导致p3(和p1)导致错误.

Ale*_*lex 5

首先,你的界面FullName只包含一个可选属性,基本上它使它匹配任何东西.然后当你用它做一个联合类型时,结果类型将与所有东西兼容.

但是,考虑声明和分配文字对象还有另外一个问题,那就是你只能声明已知属性:为什么我会收到错误"对象文字只能指定已知属性"?

所以你可以毫无问题地做到这一点:

var test = { otherStuff: 23 };
const p4: Person = test;
Run Code Online (Sandbox Code Playgroud)

但不是这个

const p4: Person = { otherStuff: 23 };
Run Code Online (Sandbox Code Playgroud)

在你的情况下firstName是一个已知的属性FullName | Name,所以一切都好.

正如@artem回答的discriminated unions那样,除了常规的工会之外,在打字稿中有特殊的含义,需要特殊的结构假设.


art*_*tem 2

从通常意义上讲,您问题中的类型不是受歧视的联合 - 您的联合成员没有称为discriminant 的通用、非可选文字属性。

因此,正如 @Alex 在他的回答中指出的那样,你的工会有点类似于

type Person = {
  fullName?: string
  firstName?: string
  lastName?: string
}
Run Code Online (Sandbox Code Playgroud)

所以它可以初始化{ firstName: 'test' }

使用真正的可区分联合,您可以恢复检查非可选属性的逻辑,以及检查对象文字是否只能指定已知属性:

interface FullName {
  kind: 'fullname';  
  fullName?: string
}

interface Name {
  kind: 'name';  
  firstName: string
  lastName: string
}

type Person = FullName | Name;

const p1: Person = {kind: 'fullname'};  // ok
const p2: Person = {kind: 'fullname', fullName: 'test' };  // ok
Run Code Online (Sandbox Code Playgroud)

检查非可选属性:

const p3: Person = {kind: 'name', firstName: 'test' }; 
Run Code Online (Sandbox Code Playgroud)

错误:

Type '{ kind: "name"; firstName: string; }' is not assignable to type 'Person'.
  Type '{ kind: "name"; firstName: string; }' is not assignable to type 'Name'.
    Property 'lastName' is missing in type '{ kind: "name"; firstName: string; }'.
Run Code Online (Sandbox Code Playgroud)

检查额外的属性:

const p5: Person = { kind: 'fullname', bar: 42 }
Run Code Online (Sandbox Code Playgroud)

错误:

Type '{ kind: "fullname"; bar: number; }' is not assignable to type 'Person'.
  Object literal may only specify known properties, and 'bar' does not exist in type 'Person'.
Run Code Online (Sandbox Code Playgroud)

然而,正如 @JeffMercado 发现的那样,类型检查仍然有点不对劲:

const p6: Person = { kind: 'fullname', firstName: 42 };  // no error. why?
Run Code Online (Sandbox Code Playgroud)

我会考虑发布 typescript github 项目的问题。