联合类型
联合类型(Union Types)
用于表示一个值可以是多个类型之一。使用竖线|
将多个类型组合起来形成联合类型
变量联合类型
let x: string | number;
x = "hello";
// 合法
x = 123;
// 合法
x = true;
// 错误,不能将类型“boolean”分配给类型“string | number”。
函数参数联合类型
function printId(id: string | number) {
console.log(id);
}
printId("abc");
// 输出:abc
printId(123);
// 输出:123
printId(true);
// 错误,类型“boolean”的参数不能赋给类型“string | number”的参数。
类型断言来处理联合类型
function getLength(strOrArr: string | number[]): number {
if (typeof strOrArr === "string") {
return strOrArr.length;
} else {
return strOrArr.length;
}
}
console.log(getLength("hello"));
// 输出:5
console.log(getLength([1, 2, 3, 4, 5]));
// 输出:5
上面的代码看起来都很好理解,我们继续看下面的例子
对象联合类型
type A = {
a: number;
b: number;
};
type B = {
b: number;
c: number;
};
type C = A | B;
const c: C = {
a: 1,
b: 2,
c: 3,
};
console.log(c.b); // 输出 2
console.log(c.a);
// 错误 类型“C”上不存在属性“a”。类型“B”上不存在属性“a”。
console.log(c.c);
// 错误 类型“C”上不存在属性“c”。类型“A”上不存在属性“c”。
const d: C = {
a: 1,
b: 2,
};
const e: C = {
b: 1,
c: 2,
};
const f: C = {
a: 1,
};
/**
* 错误 不能将类型“{ a: number; }”分配给类型“C”。
类型 "{ a: number; }" 中缺少属性 "b",但类型 "A" 中需要该属性。ts(2322)
1.ts(3, 3): 在此处声明了 "b"。
*/
const g: C = {
c: 2,
};
/**
* 不能将类型“{ c: number; }”分配给类型“C”。
* 类型 "{ c: number; }" 中缺少属性 "b",但类型 "B" 中需要该属性。ts(2322)
* 1.ts(6, 3): 在此处声明了 "b"。
*/
- 上面的代码当我们定义
c
对象引用C
类型时依次写出A
和B
的所有属性,这时候并不会抛出异常,但当我们获取c.a
和c.c
时抛出异常,这是因为在使用联合类型时,我们只能使用联合类型中所有类型共有的属性和方法
。这样可以确保类型安全 - 在联合类型中定义中,定义的值可以是多个类型中
其中一个类型
的成员,也可以时多个类型
的成员c
的赋值 {a: 1, b: 2, c: 3} 包含了A
类型的成员 a 和 b,以及B
类型的成员 b 和 c,因此满足了C
的定义,不会报错
d
的赋值 {a: 1, b: 2} 包含了A
类型的成员 a 和 b,没有C
类型中定义的 c 成员,但是因为C
是A
和B
的联合类型,所以满足了C
的定义,不会报错
e
的赋值 {b: 1, c: 2} 包含了B
类型的成员 b 和 c,没有A
类型中定义的 a 成员,但是因为C
是A
和B
的联合类型,所以满足了C
的定义,不会报错
f
的赋值 {a: 1} 只包含了A
类型的成员a,没有B
类型中定义的成员 b 和 c,因此不满足C
的定义,会报错
g
的赋值 {c: 2} 只包含了B
类型的成员 c,没有A
类型中定义的成员 a 和 b,因此不满足C
的定义,会报错
根据上述代码和解释说明,c、d、e、f、h 都是类型为
C
的变量。C
类型是A
和B
的联合类型,因此它可以是类型A
的成员、类型B
的成员,也可以是类型A
和类型B
类型的所有成员*
交叉类型
交叉类型(Intersection Types)
允许我们将多个类型合并为一个新的类型。使用&
符号将多个类型定义组合在一起形成交叉类型
合并接口的成员
interface Dog {
woof(): void;
}
interface Cat {
meow(): void;
}
type DogCat = Dog & Cat;
const animal: DogCat = {
woof() {
console.log("Woof");
},
meow() {
console.log("Meow");
},
};
animal.woof(); // 输出:Woof
animal.meow(); // 输出:Meow
合并对象的属性
const person = {
name: "Alice",
age: 30
};
const employee = {
company: "ABC Inc.",
salary: 5000
};
type PersonEmployee = typeof person & typeof employee;
const manager: PersonEmployee = {
...person,
...employee
};
console.log(manager.name); // 输出:Alice
console.log(manager.age); // 输出:30
console.log(manager.company); // 输出:ABC Inc.
console.log(manager.salary); // 输出:5000
对象交叉类型
type A = {
a: number;
b: number;
};
type B = {
b: number;
c: number;
};
type C = A & B;
const c: C = {
a: 1,
b: 2,
c: 3,
};
console.log(c.a); // 输出 2
console.log(c.b); // 输出 2
console.log(c.c); // 输出 3
const d: C = {
a: 1,
b: 2,
};
/**
* 不能将类型“{ a: number; b: number; }”分配给类型“C”。
* 类型 "{ a: number; b: number; }" 中缺少属性 "c",但类型 "B" 中需要该属性。ts(2322)
* 1.ts(7, 3): 在此处声明了 "c"。
*/
const e: C = {
b: 1,
c: 2,
};
/**
* 不能将类型“{ b: number; c: number; }”分配给类型“C”。
* 类型 "{ b: number; c: number; }" 中缺少属性 "a",但类型 "A" 中需要该属性。ts(2322)
* 1.ts(2, 3): 在此处声明了 "a"。
*/
const f: C = {
a: 1,
};
/**
* 不能将类型“{ a: number; }”分配给类型“C”。
* 类型 "{ a: number; }" 中缺少属性 "b",但类型 "A" 中需要该属性。ts(2322)
* 1.ts(3, 3): 在此处声明了 "b"。
*/
const g: C = {
c: 2,
};
/**
* 不能将类型“{ c: number; }”分配给类型“C”。
* 类型“{ c: number; }”缺少类型“A”中的以下属性: a, bts(2322)
*/
- 在联合类型中定义中,定义的值必须满足
所有类型
的成员c
的赋值 {a: 1, b: 2, c: 3} 包含了类型A
中定义的 a 和 b 成员,以及类型B
中定义的 b 和 c 成员。因此,它满足了类型C
的定义,是一个有效的赋值d
的赋值 {a: 1, b: 2},它只包含了类型A
中定义的 a 和 b 成员,没有包含类型B
中定义的 c 成员。因此,它不满足类型C
的定义,会报错
e
的赋值 {b: 1, c: 2},它只包含了类型B
中定义的 b 和 c 成员,没有包含类型A
中定义的 a 成员。因此,它不满足类型C
的定义,会报错
f
的赋值 {a: 1},它只包含了类型A
中定义的 a 成员,没有包含类型B
中定义的 b 和 c 成员。因此,它不满足类型C
的定义,会报错
g
的赋值 {c: 2},它只包含了类型B
中定义的 c 成员,没有包含类型A
中定义的 a 和 b 成员。因此,它不满足类型C
的定义,会报错
根据上述代码和解释说明,c、d、e、f、h 都是类型为
C
的变量。C类型是A
和B
的交叉类型,这意味着C
类型的变量需要同时满足
类型A
和类型B
的成员