联合类型
联合类型表示取值可以为多种类型中的一种,使用 |
分割每个类型。
let a: number | string | boolean;
a = 100;
a = 'xman';
a = true;
函数中使用:
const test = (info: string | number) => {
// ...
}
约束取值
const num: 1 | 2 = 1;
type isMan = true | false;
type EventNames = 'click' | 'scroll' | 'mousemove';
以上1 | 2, true | false, 'click' | 'scroll' | 'mousemove'被称为字面量类型,分别为数字、布尔、字符串字面量类型,可以用来约束取值只能是其中几个值中的一个。
交叉类型
交叉类型是将多个类型合并为一个类型,使用&
定义交叉类型。
可以将多个接口类型合并成一个类型,实现等同于接口继承的效果
interface A {
name: string;
age: number;
}
interface B {
name: string;
height: string;
}
type Person = A & B; // 相当于求并集
let person: Person = { name: 'xman', age: 18, height: '60kg'};
注意:
原子类型可以合并吗?
如果仅仅把基本类型、字面量类型、函数类型等原子类型合并成交叉类型,是没有任何用处的。因为任何类型都不能满足同时属于多种原子类型。type Useless = string & number; // 就是个never
合并的接口类型存在同名属性是什么效果?
如果同名属性的类型兼容,比如一个是number,另一个是number的子类型、数字字面量类型,合并后属性的类型就是两者中的子类型。interface A { name: string; age: number; id: number; } interface B { name: string; height: string; id: string; } type Person = A & B; let person: Person = { name: 'xman', age: 18, height: '60kg', id: 1}; // Type 'number' is not assignable to type 'number & string'. // Type 'number' is not assignable to type 'string'.
以上代码提示name属性值出现类型错误。
interface A { name: string; age: number; id: number; } interface B { name: string; height: string; id: 1; // 数字字面量类型为1 } type Person = A & B; let person: Person = { name: 'xman', age: 18, height: '60kg', id: 1};
以上代码中interface B的name属性的类型就是数字字面量类型1,因此我们不能把任何非1之外的值赋值为id属性;
下面看下同名属性非基本数据类型的合并情况:interface A { info: { name: string } } interface B { info: { age: number } } interface C { info: { bool: boolean } } type ABC = A & B & C; let abc: ABC = { info: { name: 'xman', age: 18, bool: true } }
编译成功,结果如下:
var abc = { info: { name: 'xman', age: 18, bool: true } };
类型别名
type: 其作用就是给类型起一个新名字,可以作用于原始值(基本类型)、联合类型、元祖以及其他任何你需要手写的类型。
例子:// 基本类型 type Num = Number; let n: Num = 1; // 联合类型 type Shape = { kind: "circle"; radius: number } | { kind: "square"; x: number } | { kind: "triangle"; x: number; y: number }; function area(s: Shape) { if (s.kind === "circle") { return Math.PI * s.radius * s.radius; } else if (s.kind === "square") { return s.x * s.x; } else { return (s.x * s.y) / 2; } } // 对象 type UserInfo = {name: string}; // 函数 type GetInfo = () => string; // 元祖 type Size = [number, number]; let x: Size = [10, 99.9];
注意:
起别名不会新建一个类型 - 它创建了一个新 名字来引用那个类型。给基本类型起别名通常没什么用。
type与interface区别
1. 都可以描述一个对象或者函数
interface
interface IPerson {
name: string;
age: number;
}
interface SetPerson {
(name: string, age: number):void;
}
type
type Person = {
name: string;
age: number;
}
type SetPerson = (name: string, age: number) => void;
注:
在ts编译成js后,所有的接口和type 都会被擦除掉
2. 拓展
接口可以扩展,但type不能extends和implement,但是type可以通过交叉类型实现interface的extends行为。interface 可以extends type,同时type也可以与interface类型交叉
interface extends interface, type 交叉类型可以实现
interface IAnimal { name: string; } interface IPerson extends IAnimal{ age: number; } // type 交叉类型可以实现 type Animal = { name: string; } type Person = Animal & { age: number};
interface extends type, type 与 interface 交叉
type Animal = { name: string; } interface IPerson extends Animal { age: number; } // type 与 interface 交叉 interface IAnimal { name: string } type Person = IAnimal & { age: number; }
3. Implements
类可以以相同的方式实现接口或类型别名。但是请注意,类和接口被认为是静态的。因此,它们不能实现/扩展命名联合类型的类型别名
interface Point { x: number; y: number; } class SomePoint implements Point { x: 1; y: 2; } type Point2 = { x: number; y: number; }; class SomePoint2 implements Point2 { x: 1; y: 2; } type PartialPoint = { x: number; } | { y: number; }; // A class may only implement another class or interface. class SomePartialPoint implements PartialPoint { x: 1; y: 2; }
4. extends class
类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。
class Point { x: number; y: number; } interface Point3d extends Point { z: number; }
5. type可以声明基本类型别名、联合类型、元祖等类型
type Num = Number; // 联合类型 type Shape = { kind: "circle"; radius: number } | { kind: "square"; x: number } | { kind: "triangle"; x: number; y: number }; // 元祖 type Size = [number, number];
type还可以使用typeof获取实例的类型进行赋值
let div = document.createElement('div'); type B = typeof div;
6. 声明合并
接口可以定义多次,并将被视为单个接口(即所有声明属性的合并),而type不能定义多次
interface IPerson { name: string; age: number; } interface IPerson { height: string; } let person:IPerson = { name: 'xman', age: 18, height: '60kg' }
7. 映射类型
type 能使用in关键字生成映射类型,但interface不行
语法与索引签名的语法类型,内部使用了 for .. in。 具有三个部分:
- 类型变量 K,它会依次绑定到每个属性。
- 字符串字面量联合的 Keys,它包含了要迭代的属性名的集合。
属性的结果类型。
type Keys = 'name' | 'height'; type Person = { [key in Keys]: string; // 类型for... in } let person: Person = { name: 'xman', height: '60kg' }
其他
export default interface IPerson { name: string; age: number; } type Person = { name: string; } export default Person;
参考资料
https://www.tslang.cn/docs/handbook/declaration-merging.html
Interfaces vs Types in TypeScript - Stack Overflow
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。