当使用可能是两种联合类型的参数调用函数时,有没有办法让TypeScript编译器产生错误?例如:
interface Name {
name: string
}
interface Email {
email: string
}
type NameOrEmail = Name | Email
function print(p: NameOrEmail) {
console.log(p)
}
print({name: 'alice'}) // Works
print({email: 'alice'}) // Works
print({email: 'alice', name: 'alice'}) // Works, but I'd like it to fail
print({email: 'alice', age: 33}) // Doesn't work
答案 0 :(得分:4)
您可以使用方法重载:
interface Name {
name: string
}
interface Email {
email: string
}
function print(p: Name): void;
function print(p: Email): void;
function print(p: Name | Email) {
console.log(p);
}
print({name: 'alice'}) // Works
print({email: 'alice'}) // Works
print({email: 'alice', name: 'alice'}) // Doesn't work
print({email: 'alice', age: 33}) // Doesn't work
这基本上会使方法实现的签名"不可见"到你的其余代码。
<强> Demo 强>
修改强>
正如@str在严格模式中所指出的,重载签名需要指定返回类型。只要它与可见签名中指定的返回类型兼容,实现仍然可以推断它的返回类型。
答案 1 :(得分:3)
TypeScript不支持排他性联合类型。
这里提出的语法和讨论存在一个未解决的问题:Proposal: Allow exclusive unions using logical or (^) operator between types
答案 2 :(得分:2)
在联合类型上执行对对象文字的多余属性检查的方式,如果联合的任何成员上存在属性,则不会触发错误。如果在您的情况下,接口不具有不兼容的属性,那么具有多余属性的对象文字将可以分配给union的任一成员,因此它将被视为有效的赋值。
避免此行为的唯一方法是使接口不兼容,例如通过在每个接口中添加具有不同值的字符串文字类型的字段:
interface Name {
type: 'n'
name: string
}
interface Email {
type: 'e'
email: string
}
type NameOrEmail = Name | Email
function print(p: NameOrEmail) {
console.log(p)
}
print({ name: 'alice', type: 'n' }) // Works
print({ email: 'alice', type: 'e' }) // Works
print({ email: 'alice', name: 'alice', type: 'e' }) //Will fail
print({ email: 'alice', age: 33, type: 'e' }) // Doesn't work
答案 3 :(得分:0)
这里是另一个示例:
export type UnionType = Type1 | Type2;
export interface Type1 {
command: number;
}
export interface Type2 {
children: string;
}
export const unionType: UnionType = {
command: 34234,
children: [{ foo: 'qwerty' }, { asdf: 'zxcv' }], // <-- this is fine for Typescript!
};