本帖最后由 AreYouGlad 于 2017-12-20 11:53 编辑
接口
作用
在编写大型项目时, 我们可能需要先设计一下这个项目的构成, 比如需要那些模块, 实现那些类, 每个类有那些功能 那么在设计的过程中我们可以使用代码进行记录与描述, 这些简单的代码就是接口 接口不会实现任何具体的业务逻辑, 它的作用就是用来规范或提醒将来如何实现 使用接口还有很多好处, 比如下面这个人使用接口后的评价
语法与特性
[AppleScript] 纯文本查看 复制代码 interface Person {
name: string;
age: number;
gender: string = '男'; // 报错, 接口里的属性不能赋值
say(): void;
study(): void;
run(): void{ console.log('跑') } // 报错, 接口里的方法不能实现
}
使用范例
用接口约束类
我们先使用interface设计一个接口, 里面描述某种类应该有的属性与方法, 然后我们再根据接口去实现对应的类 同时为了让工具能够自动帮我们分析实现的对不对,有没有缺失, 可以在类上使用implements关键接口
[AppleScript] 纯文本查看 复制代码 // 使用接口定义Person类应该有的属性与方法
interface PersonInterface {
name: string;
age: number;
eat(food: string): void;
}
// 当真正编写Person类时, 使用implements关联对应的接口, 以约束我们的实现
class CNPerson implements PersonInterface {
// 如果不添加name或age就会报错, 多添加不会报错
constructor(public name: string, public age: number, public gender: string) {}
// 不实现这个方法就会报错
eat(food: string): void {
console.log('我要吃${food}');
}
// 多实现不会报错
say(): void {
console.log(`我是${this.name}`);
}
}
用接口约束字面量对象
我们在定义变量时, 如果想限制这个变量可存储的对象具体结构, 那么变量的类型可以为某个接口的名称 注意: 接口类型的变量, 必须严格按照接口的定义数据结构进行赋值,多了少了都不行
[AppleScript] 纯文本查看 复制代码 interface data {
a: number,
b: string
};
let obj: data = { a: 10, b: 'abc' }; // 正常, 这个对象符合接口data定义的数据结构
let obj2: data = { a: 10 }; // 报错, 缺失b属性
let obj3: data = { a: 10, b: true }; // 报错, b属性类型不对
let obj4: data = { a: 10, b: true, c:1 }; // 报错, 多了c属性 泛型
为什么要泛型
- 假设有一个方法,可以传入任意多个数字,组成数组并返回
[AppleScript] 纯文本查看 复制代码 function createArray(...arg: number[]): number[] {
return arg;
}
假设我们现在要改造这个函数,让它可以实现更多需求,变得更通用 改造需求是:传入的参数可以是数字,也可以是字符串等其他任意类型 但是必须保证所有的参数类型一致,同时返回该类型构成的数组
[AppleScript] 纯文本查看 复制代码 function createArray(...arg: any[]): any[] {
return arg;
}
- 你可能会像上面那样写,但显然,这不能保证参数的类型是一致的
使用泛型
[AppleScript] 纯文本查看 复制代码 function createArray<Type>(...arg: Type[]): Type[] {
return arg;
}
let arr1: Array<number> = createArray<number>(10, 20, 30); // 正确
let arr2: Array<string> = createArray<string>('a', 'b', 'c') // 正确
let arr3: Array<any> = createArray<string>('a', 'b', 10) // 报错
泛型在类中的应用[AppleScript] 纯文本查看 复制代码 class Cache {
private data = {};
set(key: string, val: any) {
this.data[key] = val;
}
get(key: string): any {
return this.data[key];
}
}
let c: Cache = new Cache();
c.set('小红', 10);
c.get('小红');
假设现在需求变了, 要求每个缓存只能存储同一种类型的数据, 那可能你需要定义多个缓存类才能满足需求, 看下面的实现
[AppleScript] 纯文本查看 复制代码 class CacheNumber {
private data = {};
set(key: string, val: number) {
this.data[key] = val;
}
get(key: string): number {
return this.data[key];
}
}
class CacheString {
private data = {};
set(key: string, val: string) {
this.data[key] = val;
}
get(key: string): string {
return this.data[key];
}
}
- 有了泛型后, 就不用向上面那样大费周折了, 而且支持的类型更多, 理论上无限
[AppleScript] 纯文本查看 复制代码 class Cache<Type> {
private data = {};
set(key: string, val: Type) {
this.data[key] = val;
}
get(key: string): Type {
return this.data[key];
}
}
let c = new Cache<string>();
c.set('小红', 10); // 报错, val必须为字符串
c.set('小红', '10'); // 正常
// 如果变量在定义便赋了值, 那么ts会自动推导变量的类型
// 如果要手动写类型的话, 必须声明一致的泛型类型, 看下面例子
let c2: Cache = new Cache<number>(); // 报错
let c3: Cache<string> = new Cache<number>(); // 报错
let c3: Cache<number> = new Cache<number>(); // 正常
使用泛型定义数组
之前我们在定义数组类型时是这样写的
[AppleScript] 纯文本查看 复制代码 let arr: number[] = [];
arr.push(10); // 正常
arr.push('abx'); // 报错
学习了泛型之后还可以这样写
[AppleScript] 纯文本查看 复制代码 let arr: Array<number> = [];
arr.push(10); // 正常
arr.push('abx'); // 报错
|
|