1.交叉类型
将多个类型合并为一个类型,合并后的类型拥有所有类型的特性,比如A & B & C同时包含了A、B、C三种类型的特性。
const obj: A & B & C; // 同时拥有A、B、C三种类型的特性
2.联合类型
联合类型与交叉类型很有关联,但使用上完全不同。如果说交叉类型是与的关系的话,那么联合类型就是或的关系了。
let count: number | string; // count被声明为既可以是number类型,也可以是string类型
count = 1; // OK
count = "1"; // OK
ps.联合类型中包含的是所有类型中的共有成员。
3.类型保护与区分类型
(1)用户自定义的类型保护
简单来说就是定义一个函数,它的返回值是一个类型谓词,形如parameterName is Type,parameterName必须是当前函数签名中的一个参数名。
function isFun(fun: Fun | Object): pet is Fun {
return (<Fun> fun).run !== undefined;
}
(2)使用typeof类型保护
if(typeof fun === "Fun") {
fun.run();
}
(3)使用instanceof类型保护
if(fun instanceof Fun) {
fun.run();
}
4.可能为null的类型
TypeScript具有两种特殊的类型,null和undefined,它们分别具有null和undefined。默认情况下,null与undefined可以赋值给任何类型。可以使用联合类型明确的包含它们,这样在声明一个变量时,它不会自动地包含null或undefined。
let str: string | null = "str";
str = null; // OK
str = undefined; // Error
(1)可选参数和可选属性
可选参数和可选属性会被自顶加上| undefined。
function fun(x?: number) {
return x;
}
function(1); // OK
function(undefined); // OK
function(null); // Error
class A {
a?: number;
}
const a = new A();
a.a = 1; // OK
a.a = undefined; // OK
a.a = null; // Error
(2)类型保护和类型断言
因为可以为null的类型是通过联合类型实现的,因此需要使用类型保护来去除null。
function fun(str: string | null) {
if(str === null) {
return "default";
}
return str;
}
// 或者
function fun(str: string | null) {
return str || "default";
}
如果编译器不能去除null或undefined,我们可以使用类型断言手动去除,语法是在变量名后面添加!。
function fun(name: string | null) {
return name!.charAt(0);
}
5.类型别名
顾名思义就是给类型起一个别名,实际上就是创建了一个指向源类型的引用。
type Str = string;
let str: Str = "str";
type Contanier<T> = { value: T };
type Tree<T> = {
value: T;
left: Tree<T>,
right: Tree<T>
}
(1)接口与类型别名的区别
- 接口创建了一个新的名字,类型别名不创建新的名字(错误信息会指向源类型,而不是别名)
- 别名不能被继承和实现
6.字面量类型
(1)字符串字面量类型
type Easing = "ease-in" | "ease-out" | "ease-in-out";
let str: Easing;
str = "ease-in"; //OK
str = "ease" //Error
(2)数字字面量类型
type Easing = 1 | 2 | 3;
let num: Easing;
num = 1; // OK
num = 4; // Error
7.可辨识联合
在可辨识联合中,我们声明了三个接口,这三个接口中都拥有相同的属性kind,但是不同接口中kind拥有不同的字符串字面量类型,因此kind被称为可辨识的特征或标签。
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
function area(s: Shape) {
switch (s.kind) {
case "square": return s.size * s.size;
case "rectangle": return s.height * s.width;
case "circle": return Math.PI * s.radius ** 2;
}
}
8.索引类型
(1)索引类型查询
使用keyof操作符可以将一个类型上的所有公共属性名组合为一个联合类型。
let person: Person = {
name: 'Jarid',
age: 35
};
let type = keyof Person; // 'name' | 'age'
(2)索引访问操作符
使用索引访问操作符则是限制了返回值只能是类型上的索引。
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
return o[name]; // o[name] is of type T[K]
}
9.映射类型
一个常见的任务就是将一个已知的类型的每个属性都变为可选的,或者我们只需要一个只读的版本
type Readonly<T> = {
readonly [P in keyof T]: T[P];
}
type Partial<T> = {
[P in keyof T]?: T[P];
}