【TS】加深TS理解的开发实战示例代码
文章目录
- TS接口
- 开发实战:基于类类型接口设计实现日期时间应用
- 开发实战:基于单接口继承设计实现计算周长的应用
- 开发实战:基于多接口继承设计实现计算周长和面积的应用
- 开发实战:基于混合类型接口设计实现计数器应用
- TypeScript类
- 开发实战:设计实现存取器应用
- TypeScript 函数
- 开发实战:箭头函数与this关键字应用
- TypeScript 泛型
- 开发实战:泛型变量应用
- 开发实战:泛型类型应用
- 开发实战:泛型接口应用
- 开发实战:泛型类应用
- TypeScript 高级类型
- 类型别名
- 映射类型
TS接口
开发实战:基于类类型接口设计实现日期时间应用
interface ITimeDate {curTime: Date;setTime(cur: Date): void;getTime(): Date;
}class CTime implements ITimeDate {curTime: Date;constructor(cur: Date) {this.curTime = cur;}setTime(cur: Date): void {this.curTime = cur;}getTime(): Date {let curTime: Date;if(this.curTime) {curTime = this.curTime;} else {curTime = new Date();}return curTime;}
}let ct: CTime = new CTime(new Date());
console.log(ct.getTime());let newTime: Date = new Date("2021/10/21 00:00:00");
ct.setTime(newTime);
console.log("New time is: " + ct.getTime());
开发实战:基于单接口继承设计实现计算周长的应用
interface IShape {girth: number;
}
interface ISqure extends IShape {shapeType: string;getGirth(): number;
}class CSquare implements ISqure {shapeType: string;girth: number;constructor(sideLength: number) {this.shapeType = 'Square';this.girth = sideLength * 4;}getGirth(): number {return this.girth;}
}let cs: CSquare = new CSquare(6);
console.log(cs.shapeType + 'sideLength is 6, then girth is ' + cs.getGirth() + '.'
);
声明了一个表示几何图形的抽象接口IShape,其中包括一个表示图形周长的属性girth.
同时声明了一个继承自抽象接口IShape的接口ISquare,用来描述正方形。
最后定义了一个实现接口ISquare的类CSquare。
开发实战:基于多接口继承设计实现计算周长和面积的应用
前一个应用是通过单接口继承实现的,其实TypeScript多接口继承功能更常用。
我们对上述示例进行改进,通过TypeScript多接口继承设计实现同时计算正方形周长和面积的应用。
interface IGirth {girth: number;
}
interface IArea {area: number;
}interface ISquareB extends IGirth, IArea {shapeType: string;getGirth(): number;getArea(): number;
}
class CSquareB implements ISquareB {shapeType: string;girth: number;area: number;constructor(sideLength: number) {this.shapeType = "Square";this.girth = 4 * sideLength;this.area = sideLength * sideLength;}getGirth(): number {return this.girth;}getArea(): number {return this.area;}
}let csB: CSquareB = new CSquareB(6);
console.log(csB.shapeType + " sideLength is 6, then girth is " + csB.getGirth() + ".");
console.log(csB.shapeType + " sideLength is 6, then area is " + csB.getArea() + "." );
开发实战:基于混合类型接口设计实现计数器应用
下面通过TypeScript混合类型接口设计实现一个具有计数器(初始化、累加、调整步长和重置)功能的应用。
interface ICounter {(s: string): void;current: number;interval: number;count(): void;setInterval(i: number): void;reset(): void;
}function getCounter(): ICounter {let counter = <ICounter>function(s: string): void {console.log(s);}// init countercounter.current = 0;counter.interval = 1;counter.count = function() {counter.current += counter.interval;console.log('Now current count is: ' + counter.current + '.');}counter.setInterval = function(i: number) {counter.interval = i;console.log('Now interval changes to:' + counter.interval + '.');}counter.reset = function() {counter.current = 0;console.log('Now current count is reset to 0.');}return counter;
}let c = getCounter();
console.log('counter typescript app:');
c.count();
c.setInterval(5);
c.count();
c.reset();
c.setInterval(1);
c.count();
最终结果:
counter typescript app:
Now current count is: 1.
Now interval changes to:5.
Now current count is: 6.
Now current count is reset to 0.
Now interval changes to:1.
ICounter 接口定义了一个函数类型和一些属性和方法:
interface ICounter {(s: string): void; // 这是一个函数类型current: number; // 这是一个属性interval: number; // 这是一个属性count(): void; // 这是一个方法setInterval(i: number): void; // 这是一个方法reset(): void; // 这是一个方法
}
通过类型断言 ,我们确保 counter 变量不仅包含一个函数,还包含 current、interval 属性以及 count、setInterval 和 reset 方法。这样,TypeScript 编译器就会检查这些属性和方法是否都被正确地初始化和实现。
说明如下代码意思:
let counter = <ICounter>function(s: string): void {console.log(s);
}
- 定义一个匿名函数 function(s: string): void { console.log(s); }。
- 使用类型断言 将这个匿名函数断言为 ICounter 类型。
在 TypeScript 中,类型断言有两种语法形式:
- 使用尖括号 ,例如 。
- 使用 as 关键字,例如 as ICounter。
TypeScript类
开发实战:设计实现存取器应用
在TypeScript类语法中,支持通过getters/setters存取器方式来执行对类成员的访问操作,这种方式能帮助开发人员有效地控制对类成员的访问。在TypeScript类中,设计存取器需要使用get(获取)和set(存储)修饰符来定义。
class CGetSet {private _name: string;constructor(theName: string) {this._name = theName;}get Name(): string {return this._name;}set Name(theName: string) {theName = theName.trim();if(theName && theName.length) {this._name = theName;} else {console.log('error:theName is empty.');}}
}let gs = new CGetSet('set&get');
console.log(gs.Name); // set&get
gs.Name = 'reset set&get';
console.log(gs.Name); // reset set&get
TypeScript 函数
开发实战:箭头函数与this关键字应用
let userInfo = {uname: 'zhangsan',printInfo() {return function () {return {name: this.uname}}}
}const ui = userInfo.printInfo();
console.log(ui().name)
上面代码中this会报错,编译信息提示this关键字的类型为Any的错误。
方式一,用箭头函数调整:
let userInfo = {uname: 'zhangsan',printInfo() {return () => {return {name: this.uname}}}
}const ui = userInfo.printInfo();
console.log(ui().name)
方式二,使用 that 或 self 变量:
let userInfo = {uname: 'zhangsan',printInfo() {const self = this;return function () {return {name: self.uname}}}
}
方式三:使用 apply 或 call 方法
可以在调用嵌套函数时使用 apply 或 call 方法来显式设置 this。
let userInfo = {uname: 'zhangsan',printInfo() {return function (this: typeof userInfo) {return {name: this.uname}}}
}const ui = userInfo.printInfo();
console.log(ui.apply(userInfo).name)
TypeScript 泛型
开发实战:泛型变量应用
function echoVar<T>(arg: Array<T>): Array<T> {console.log('arg length:' + arg.length)return arg;
}console.log(echoVar([1, 2]))
console.log(echoVar(['a', 'b']))
上述代码定义了一个泛型函数echoVar,参数arg定义为类型<T>的数组形式Array<T>。
开发实战:泛型类型应用
使用泛型类型定义泛型函数的应用
function echo_type<T>(arg: T): T {return arg;
}let arrow_echo_type: <T>(arg:T) => T = echo_type;console.log(arrow_echo_type("Hello")); // Hello
上述代码,通过泛型类型<T>(arg:T)定义了一个泛型函数变量arrow_echo_type,并指定为泛型函数echo_type。
另外,我们可以使用具有调用签名的对象字面量来定义泛型函数:
function echo_type<T>(arg: T): T {return arg;
}let liter_echo_type: {<T>(arg:T):T} = echo_type;
console.log(liter_echo_type("Hello")); // Hello
开发实战:泛型接口应用
我们可以将对象字面量“{<T>(arg:T):T}”单独封装为一个接口形式。
interface IGenericsEcho {<T>(arg: T): T;
}function fn_echo_generics<T>(arg: T): T {return arg;
}let echo_gen: IGenericsEcho = fn_echo_generics;
console.log(echo_gen('define generics func by interface'));
上述代码,声明了一个接口IGenericsEcho,通过对象字面量“<T>(arg:T):T”定义了泛型函数的类型。
通过泛型接口IGenericsEcho和泛型函数fn_echo_generics定义了一个函数变量echo_gen。
进一步在接口声明中直接加上类型<T>,写成真正的泛型接口形式。上述代码调整为如下:
interface IGenericsEcho<T> {(arg: T): T;
}function fn_echo_generics<T>(arg: T): T {return arg;
}let echo_gen_str: IGenericsEcho<string> = fn_echo_generics;
let echo_gen_num: IGenericsEcho<number> = fn_echo_generics;
console.log(echo_gen_str('define generics func by interface'));
console.log(echo_gen_num(123));
上面代码声明了一个泛型接口IGenericsEcho<T>,接口类型为“(arg:T):T”。
我们在使用该泛型接口定义函数变量echo_gen_num和echo_gen_str时,需要指定具体类型。
开发实战:泛型类应用
class EchoGenerics<T> {private _m_arg: T;constructor(arg: T) {this._m_arg = arg;}public echo(): void {console.log(this._m_arg)}
}let g_echo_str = new EchoGenerics<string>("Hello World");
g_echo_str.echo();
let g_echo_num = new EchoGenerics<number>(123);
g_echo_num.echo();
TypeScript 高级类型
类型别名
在类型别名中使用泛型来模拟接口功能的应用。
type StrNum = string | number;
type aliasGeneric<T> = {x: T;y: T;
}function getXY(ag: aliasGeneric<StrNum>) {if(typeof ag.x === 'number' && typeof ag.y === 'number') {console.log(ag.x + ag.y)}else if(typeof ag.x === 'string' && typeof ag.y === 'string') {console.log(`${ag.x} ${ag.y}`)}else {console.log('other alias-type generic')}
}let agStr: aliasGeneric<string> = {x: 'a',y: 'b'
}
getXY(agStr);let agNum: aliasGeneric<number> = {x: 1,y: 2
}
getXY(agNum);
映射类型
如下示例,通过映射类型方式将原接口IPerson的属性转换为只读属性:
interface IPerson {name: string;age: number;
}type TReadyOnly<T> = {readonly [p in keyof T]: T[p];
}type ReadyOnlyPerson = TReadyOnly<IPerson>;
通过映射类型方式将原接口IPerson的属性转换为可选属性:
interface IPerson {name: string;age: number;
}type TOptional<T> = {[p in keyof T]?: T[p];
}type OptionalPerson = TOptional<IPerson>;