考虑以下类型:
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;
我希望p3
导致编译错误,因为firstName
不存在lastName
,但它没有 - 这是一个错误还是预期?
此外,要求使用FullName.fullName导致p3
(和p1
)导致错误。
答案 0 :(得分:5)
首先,你的界面FullName
只包含一个可选属性,它基本上使它匹配任何东西。然后当你用它做一个联合类型时,结果类型将与所有东西兼容。
然而,考虑声明和分配文字对象还有另一个问题,那就是您只能声明已知属性:Why am I getting an error "Object literal may only specify known properties"?
所以你可以毫无问题地做到这一点:
var test = { otherStuff: 23 };
const p4: Person = test;
但不是这个
const p4: Person = { otherStuff: 23 };
在您的情况下,firstName
是FullName | Name
的已知属性,所以一切正常。
正如@artem回答的那样,discriminated unions
除了常规的工会之外,在打字稿中有特殊含义,需要特殊的结构假设。
答案 1 :(得分:2)
在通常意义上,您的问题中的类型不是受歧视的联盟 - 您的工会成员不具有称为discriminant的共同的,非可选的文字属性。
所以,正如@Alex在他的回答中指出的,你的联盟有点类似于
type Person = {
fullName?: string
firstName?: string
lastName?: string
}
因此可以使用{ 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
检查非可选属性:
const p3: Person = {kind: 'name', firstName: 'test' };
错误:
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; }'.
检查额外属性:
const p5: Person = { kind: 'fullname', bar: 42 }
错误:
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'.
然而,正如@JeffMercado发现的那样,类型检查仍然有点过时了:
const p6: Person = { kind: 'fullname', firstName: 42 }; // no error. why?
我考虑为typescript github项目发布一个问题。
答案 2 :(得分:0)
2021 年更新:问题中的示例现在按预期工作。
至少因为 TypeScript 版本 3.3.3
(目前可以在 TypeScript 游乐场上测试的最旧版本),所以您不需要判别式(即常见的、非可选的文字属性)。
给定
interface FullName {
fullName?: string
}
interface Name {
firstName: string
lastName: string
}
type Person = FullName | Name;
在问题中,以下示例(被提出此问题的人标记为“不抛出”)
const p3: Person = { firstName: 'test' }; // Does not throw
现在导致此 TypeScript 错误:
Property 'lastName' is missing in type '{ firstName: string; }' but required in type 'Name'.
@artem 想知道为什么
const p6: Person = { kind: 'fullname', firstName: 42 };
不会在他的示例中使用判别式 kind
抛出错误。
好吧,自从最后一个 TypeScript 版本 3.3.3 它确实抛出了一个错误,正是预期的错误:
Object literal may only specify known properties, and 'firstName' does not exist in type 'FullName'.
参见 this TypeScript playground,其中包括两个示例(有和没有歧视联合)。