一、什么是接口
https://segmentfault.com/a/1190000010979494
接口的声明
在前面我们通过 type 可以用来声明一个对象类型
对象的另外一种声明方式就是通过接口来声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| type InfoType = { name: string; age: number; };
interface IInfoType { name: string; age: number; }
let p: InfoType = { name: "cc", age: 79, };
let p2: IInfoType = { name: "bb", age: 90, };
export {};
|
一般以 I 开头表明是个接口。
索引类型
使用 interface 来定义对象类型,这个时候其中的属性名、类型、方法都是确定的,但是有时候我们会遇到类似下面的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| interface IndexLanguage { [index: number]: string; } const frontLanguage: IndexLanguage = { 0: "HTML", 1: "CSS", 2: "JavaScript", 3: "Vue", };
interface ILanguageYear { [name: string]: number; } const languageYear: ILanguageYear = { C: 1972, Java: 1995, JavaScript: 1996, TypeScript: 2014, };
|
函数类型
前面我们都是通过 interface 来定义对象中普通的属性和方法的,实际上它也可以用来定义函数类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
interface CalcFn { (n1: number, n2: number): number; }
function calc(num1: number, num2: number, calcFn: CalcFn) { return calcFn(num1, num2); }
const add: CalcFn = (num1, num2) => { return num1 + num2; };
calc(20, 30, add);
|
除非特别的情况,还是推荐使用类型别名来定义函数
1
| type CalcFn = (n1: number, n2: number) => number;
|
交叉类型
我们学习了联合类型:
联合类型表示多个类型中一个即可
1 2 3
| type WhyType = number | string; type Direction = "left" | "right" | "center";
|
还有另外一种类型合并,就是交叉类型(Intersection Types)
交叉类似表示需要满足多个类型的条件
交叉类型使用 & 符号
我们来看下面的交叉类型
1 2
| type WType = number & string;
|
表达的含义是 number 和 string 要同时满足
但是有同时满足是一个 number 又是一个 string 的值吗?其实是没有的,所以 MyType 其实是一个 never 类型
在开发中,我们进行交叉时,通常是对对象类型进行交叉的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| interface ISwim { swimming: () => void; }
interface IFly { flying: () => void; }
type MyType1 = ISwim | IFly; type MyType2 = ISwim & IFly;
const obj1: MyType1 = { flying() {}, };
const obj2: MyType2 = { swimming() {}, flying() {}, };
|
接口的继承
接口和类一样是可以进行继承的,也是使用 extends 关键字
并且接口是支持多继承的(类不支持多继承)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| interface ISwim { swimming: () => void; }
interface IFly { flying: () => void; }
interface IAction extends ISwim, IFly {}
const action: IAction = { swimming() {}, flying() {}, };
|
接口的实现
接口定义后,也是可以被类实现的
如果被一个类实现,那么在之后需要传入接口的地方,都可以将这个类传入
这就是面向接口开发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| interface ISwim { swimming: () => void; }
interface IEat { eating: () => void; }
class Animal {}
class Fish extends Animal implements ISwim, IEat { swimming() { console.log("Fish Swmming"); }
eating() { console.log("Fish Eating"); } }
class Person implements ISwim { swimming() { console.log("Person Swimming"); } }
function swimAction(swimable: ISwim) { swimable.swimming(); }
swimAction(new Fish()); swimAction(new Person());
swimAction({ swimming: function () {} });
|
interface 和 type 的区别
我们会发现 interface 和 type 都可以用来定义对象类型,那么在开发中定义对象类型时,到底选择哪一个呢
如果是定义非对象类型
- 通常推荐使用 type,比如 Direction、Alignment、一些 Function
如果是定义对象类型,那么他们是有区别
- interface 可以重复的对某个接口来定义属性和方法
- 而 type 定义的是别名,别名是不能重复的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| interface IFoo { name: string; }
interface IFoo { age: number; }
const foo: IFoo = { name: "why", age: 18, };
document.getElementById("app") as HTMLDivElement; window.addEventListener;
interface Window { age: number; } window.age = 19; console.log(window.age);
interface IPerson {}
|
字面量赋值
TypeScript 在字面量直接赋值的过程中,为了进行类型推导会进行严格的类型限制
但是之后如果我们是将一个变量标识符赋值给其他的变量时,会进行 freshness 擦除操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| interface IPerson { name: string; age: number; height: number; }
const info = { name: "why", age: 18, height: 1.88, address: "广州市", };
const p: IPerson = info;
console.log(info); console.log(p);
function printInfo(person: IPerson) { console.log(person); }
const info1 = { name: "why", age: 18, height: 1.88, address: "广州市", };
printInfo(info1);
|
枚举类型
枚举类型是为数不多的 TypeScript 特性有的特性之一
枚举其实就是将一组可能出现的值,一个个列举出来,定义在一个类型中,这个类型就是枚举类型
枚举允许开发者定义一组命名常量,常量可以是数字、字符串类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
enum Direction { LEFT, RIGHT, TOP, BOTTOM, }
function turnDirection(direction: Direction) { switch (direction) { case Direction.LEFT: console.log("改变角色的方向向左"); break; case Direction.RIGHT: console.log("改变角色的方向向右"); break; case Direction.TOP: console.log("改变角色的方向向上"); break; case Direction.BOTTOM: console.log("改变角色的方向向下"); break; default: const foo: never = direction; break; } }
turnDirection(Direction.LEFT); turnDirection(Direction.RIGHT); turnDirection(Direction.TOP); turnDirection(Direction.BOTTOM);
|
枚举类型的值
枚举类型默认是有值的,比如上面的枚举,默认值是 0 1 2 3 ….:
当然,我们也可以给枚举其他值:
也可以给他们赋值其他的类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
enum Direction { LEFT = "LEFT", RIGHT = "RIGHT", TOP = "TOP", BOTTOM = "BOTTOM", }
let name: string = "abc"; let d: Direction = Direction.BOTTOM;
function turnDirection(direction: Direction) { console.log(direction); switch (direction) { case Direction.LEFT: console.log("改变角色的方向向左"); break; case Direction.RIGHT: console.log("改变角色的方向向右"); break; case Direction.TOP: console.log("改变角色的方向向上"); break; case Direction.BOTTOM: console.log("改变角色的方向向下"); break; default: const foo: never = direction; break; } }
turnDirection(Direction.LEFT); turnDirection(Direction.RIGHT); turnDirection(Direction.TOP); turnDirection(Direction.BOTTOM);
export {};
|