加入QQ群:864680898,一起学习进步!点击群名可查看本人网站,有最新文章!
(四)Typescript中的泛型 T, 命名空间, 装饰器
一、泛型 T
- 为什么要用泛型?
可以在函数调用时自由化传入的值和返回的值
let showInfo = <T>(val: T): T => val;
let myName = showInfo<string>('mySkey');
console.log(myName)
- 泛型类 泛型类看上去与泛型接口差不多
泛型类使用(<>)括起泛型类型,跟在类名后面
class Method<T> {
add: (x: T, y: T) => T;
}
let method = new Method<number>();
method.add = (x, y) => x+y
console.log(method.add(1,3))
- 泛型约束
有时我们要限制泛型中类型
interface Lengthwise {
name: string;
}
let showInfo = <T extends Lengthwise>(arg: T): T =>{
console.log(arg); // Now we know it has a .length property, so no more error
return arg;
}
showInfo({name: 'mySkey'});
二、命名空间
当应用变得越来越大时,我们需要将代码分离到不同的文件中以便于维护;尽管是不同的文件,它们仍是同一个命名空间,并且在使用的时候就如同它们在一个文件中定义的一样。 因为不同文件之间存在依赖关系,所以我们加入了引用标签来告诉编译器文件之间的关联
- 多文件的命名空间 (不推荐使用)
使用 /// 方式引入,这是3个 / ,不是注释
新建Person.ts文件
namespace Person {
export interface PersonInterface {
name: string;
age: number;
}
}
在同级目录下的main.ts中使用
/// <reference path="Person.ts" />
let mySkey: Person.PersonInterface = { name: 'mySkey', age: 23 }
- 别名 (推荐使用)
使用import q = x.y.z给常用的对象起一个短的名字
import myInterface = Person.PersonInterface;
let mySkey: myInterface = { name: 'mySkey', age: 23 }
- 外部命名空间
流行的程序库D3在全局对象d3里定义它的功能。 因为这个库通过一个
declare namespace D3 {
export interface Selectors {
select: {
(selector: string): Selection;
(element: EventTarget): Selection;
};
}
export interface Event {
x: number;
y: number;
}
export interface Base extends Selectors {
event: Event;
}
}
declare let d3: D3.Base;
三、Decorators 装饰器
Javascript里的装饰器目前处在建议征集的第一阶段,但在TypeScript里已做为一项实验性特性予以支持
- tsconfig.json里启用experimentalDecorators编译器选项: “experimentalDecorators”: true
{
"compilerOptions": {
"experimentalDecorators": true
}
}
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,访问符,属性或参数上。 装饰器使用@expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入,就相当于中间件
- 只有类和类里面的属性,方法,方法中的形参能使用装饰器
装饰器工厂就是一个简单的函数,它返回一个表达式,以供装饰器在运行时调用
多个装饰器调用时时遵循:
1、由上至下依次对装饰器表达式求值。
2、求值的结果会被当作函数,由下至上依次调用。
class Father {
shape: string = 'ugly';
showAge(){
console.log('80年代!')
}
}
function chageAge(age: number){
return function (target: any){
target.prototype.showAge = function () {
console.log('我是00后的,已经不是小朋友了!我今年都'+ age +'岁了')
}
}
}
@chageAge(10)
class Son extends Father{
}
let father = new Father();
let son = new Son();
father.showAge()
son.showAge()
上面这种类及其实例并不能感知或者修改存取在类上元数据,但是我们可以通过装饰器和注解在编译时动态的修改它们的行为,即我们写了一个函数去修改函数,我们把这样的行为称作元编程