八、TypeScript数组
8.1 数组解构
let x: number; let y: number; let z: number;let five_array = [0,1,2,3,4];[x,y,z] = five_array;
8.2 数组展开运算符
let two_array = [0, 1];let five_array = [...two_array, 2, 3, 4];
8.3 数组遍历
let colors: string[] = ["red", "green", "blue"];for (let i of colors) {console.log(i);}
九、TypeScript对象
9.1 对象解构
let person = {name: "btqf",gender: "Male",};let { name, gender } = person;
9.2 对象展开运算符
let person = {name: "btqf",gender: "Male",address: "Xiamen",};// 组装对象let personWithAge = { ...person, age: 33 };// 获取除了某些项外的其它项let { name, ...rest } = person;
十、TypeScript 接口
在面向对象语言中,接口是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类去实现。TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。
10.1 对象的形状
interface Person {name: string;age: number;}let btqf: Person = {name: 'btqf';age: 22;}
10.2 可选 | 只读属性
interface Person {readonly name: string;age?: number;}
10.3 任意属性
interface Person {name: string;age?: number;[propName: string]: any;}const p1 = { name: "btqf" };const p2 = { name: "lolo", age: 5 };const p3 = { name: "kakuqo", sex: 1 }
10.4 Declaration merging
接口可以定义多次,会被自动合并为单个接口。
interface Point { x: number; }interface Point { y: number; }const point: Point = { x: 1, y: 2 };
十一、TypeScript 类
在面向对象语言中,类是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法
11.1 类的属性与方法
class Greeter {// 静态属性static cname: string = "Greeter";// 成员属性:在原型链上greeting: string;// 构造函数 - 执行初始化操作constructor(message: string) {this.greeting = message;}// 静态方法static getClassName() {return "Class name is Greeter";}// 成员方法greet() {return "Hello, " + this.greeting;}}let greeter = new Greeter("world");
11.2 ECMAScript 私有字段
class Person {#name: string;constructor(name: string) {this.#name = name;}greet() {console.log(`Hello, my name is ${this.#name}!`);}}let semlinker = new Person("btqf");semlinker.#name;
私有字段存在以下规则:
- 私有字段以
#字符开头,有时我们称之为私有名称 - 每个私有字段都唯一地限定其包含的类,不能被包含的类之外访问
- 不能在私有字段上使用TypeScript可访问修饰符(如public / private)
11.3 访问器
通过setter和getter实现数据的封装和有效性检验,防止出现异常数据 ```javascript let passcode = “Hello TypeScript”;
class Employee { private _fullName: string;
get fullName(): string { return this._fullName; }
set fullName(newName: string) { if (passcode && passcode == “Hello TypeScript”) { this._fullName = newName; } else { console.log(“Error: Unauthorized update of employee!”); } } }
let employee = new Employee(); employee.fullName = “btqf”; if (employee.fullName) { console.log(employee.fullName); }
<a name="LjeGj"></a>### 11.4 类的继承通过`extends`关键字来实现继承```javascriptclass Animal {name: string;constructor(theName: string) {this.name = theName;}move(distanceInMeters: number = 0) {console.log(`${this.name} moved ${distanceInMeters}m.`);}}class Snake extends Animal {constructor(name: string) {super(name); // 调用父类的构造函数}move(distanceInMeters = 5) {console.log("Slithering...");super.move(distanceInMeters);}}let sam = new Snake("Sammy the Python");sam.move();
11.5 抽象类
使用 abstract关键字声明的类,我们称之为抽象类。抽象类不能被实例化,因为它里面包含一个或多个抽象方法。所谓的抽象方法,是指不包含具体实现的方法。
抽象类不能被直接实例化,我们只能实例化实现了所有抽象方法的子类。
abstract class Person {constructor(public name: string){}// 抽象方法abstract say(words: string) :void;}class Developer extends Person {constructor(name: string) {super(name);}say(words: string): void {console.log(`${this.name} says ${words}`);}}const lolo = new Developer("lolo");lolo.say("I love ts!"); // lolo says I love ts!
十二、TypeScript泛型
在像 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。
设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。
泛型(Generics)是允许同一个函数接受不同类型参数的一种模板。相比于使用 any 类型,使用泛型来创建可复用的组件要更好,因为泛型会保留参数类型。
12.1 泛型语法
function identity <T, U>(value: T, message: U) : T {console.log(message);return value;}console.log(identity<Number, string>(68, "Semlinker"));console.log(identity(68, "Semlinker")); // 编译器自动选择类型,省略尖括号
看到上述的代码,我们在定义identity函数时使用了 <T, U>,这其实没有什么特别的。它像传递参数一眼,我们传递了我们想要用于特定函数调用的类型。
其中 T 代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T 可以用任何有效名称代替。除了 T 之外,以下是常见泛型变量代表的意思:
- K(Key):表示对象中的键类型;
- V(Value):表示对象中的值类型;
- E(Element):表示元素类型。
12.2 泛型接口
interface GenericIdentityFn<T> {(arg:T) : T;}
12.3 泛型类
```javascript class GenericNumber{ zeroValue: T; add: (x: T, y: T) => T; }
let myGenericNumber = new GenericNumber
<a name="rPjP6"></a>### 12.4 泛型工具类型为了方便开发者 TypeScript 内置了一些常用的工具类型,比如 Partial、Required、Readonly、Record 和 ReturnType 等。这里我们只简单介绍 Partial 工具类型。1. **相关的基础知识**`typeof`/`keyof`/`in`/`infer`/`extends`2. **Partial**`Partial<T>`的作用就是将某个类型里的属性全部变为可选项`?`.```javascripttype Partial<T> = {[P in keyof T]?: T[P];};
在上面的代码中,首先通过keyof T拿到T的所有属性名,然后用in进行遍历,将值赋给P,最后通过T[P]取得相应的属性值。中间的?号,用于将所有属性变为可选。
interface Todo {title: string;description: string;}function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {return { ...todo, ...fieldsToUpdate };}const todo1 = {title: "Learn TS",description: "Learn TypeScript",};const todo2 = updateTodo(todo1, {description: "Learn TypeScript Enum",});
在上面的updateTodo方法中,我们利用Partial<T>工具类型,定义fieldsToUpdate的类型为Partial<Todo>,即:
{title?: string | undefined;description?: string | undefined;}
十三、TypeScript装饰器
13.1 装饰器是什么
- 它是一个表达式
- 该表达式被执行后,返回一个函数
- 函数的入参分别为target/name/descriptor
执行该函数,可能返回descriptor对象,用于配置target对象
13.2 装饰器的分类
类装饰器
- 属性装饰器
- 方法装饰器
-
13.3 类装饰器
类装饰器声明:
declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;
类装饰器顾名思义,就是用来装饰类的。它接收一个参数:
target: TFunction - 被装饰的类 ```javascript function Greeter(greeting: string) { return function (target: Function) { target.prototype.greet = function (): void {
console.log(greeting);
}; }; }
@Greeter(“Hello TS!”) class Greeting { constructor() { // 内部实现 } }
let myGreeting = new Greeting(); (myGreeting as any).greet(); // console output: ‘Hello TS!’;
在上面的例子中,我们定义了`Greeter`类装饰器,同时我们使用了`@Greeter`语法糖,来使用装饰器。<a name="l0fMh"></a>### 13.4 属性装饰器属性装饰器声明:```javascriptdeclare type PropertyDecorator = (target:Object,propertyKey: string | symbol ) => void;
属性装饰器顾名思义,用来装饰类的属性。它接收两个参数:
- target: Object - 被装饰的类
propertyKey: string | symbol - 被装饰类的属性名 ```javascript function logProperty(target: any, key: string) { delete target[key];
const backingField = “_” + key;
Object.defineProperty(target, backingField, { writable: true, enumerable: true, configurable: true });
// property getter const getter = function (this: any) { const currVal = this[backingField]; console.log(
Get: ${key} => ${currVal}); return currVal; };// property setter const setter = function (this: any, newVal: any) { console.log(
Set: ${key} => ${newVal}); this[backingField] = newVal; };// Create new property with getter and setter Object.defineProperty(target, key, { get: getter, set: setter, enumerable: true, configurable: true }); }
class Person { @logProperty public name: string;
constructor(name : string) { this.name = name; } }
const p1 = new Person(“semlinker”); p1.name = “kakuqo”;
以上代码我们定义了一个 logProperty 函数,来跟踪用户对属性的操作,当代码成功运行后,在控制台会输出以下结果:```javascriptSet: name => semlinkerSet: name => kakuqo
13.5 方法装饰器
方法装饰器声明:
declare type MethodDecorator = <T>(target:Object, propertyKey: string | symbol,descriptor: TypePropertyDescript<T>) => TypedPropertyDescriptor<T> | void;
方法装饰器顾名思义,用来装饰类的方法。它接收三个参数:
- target: Object - 被装饰的类
- propertyKey: string | symbol - 方法名
- descriptor: TypePropertyDescript - 属性描述符 ```javascript function log(target: Object, propertyKey: string, descriptor: PropertyDescriptor) { let originalMethod = descriptor.value; descriptor.value = function (…args: any[]) { console.log(“wrapped function: before invoking “ + propertyKey); let result = originalMethod.apply(this, args); console.log(“wrapped function: after invoking “ + propertyKey); return result; }; }
class Task { @log runTask(arg: any): any { console.log(“runTask invoked, args: “ + arg); return “finished”; } }
let task = new Task(); let result = task.runTask(“learn ts”); console.log(“result: “ + result);
以上代码成功运行后,控制台会输出以下结果:```javascript"wrapped function: before invoking runTask""runTask invoked, args: learn ts""wrapped function: after invoking runTask""result: finished"
13.6 参数装饰器
参数装饰器声明:
declare type ParameterDecorator = (target: Object, propertyKey: string | symbol,parameterIndex: number ) => void
参数装饰器顾名思义,是用来装饰函数参数,它接收三个参数:
- target: Object - 被装饰的类
- propertyKey: string | symbol - 方法名
- parameterIndex: number - 方法中参数的索引值
``javascript function Log(target: Function, key: string, parameterIndex: number) { let functionLogged = key || target.prototype.constructor.name; console.log(The parameter in position ${parameterIndex} at ${functionLogged} has been decorated`); }
class Greeter { greeting: string; constructor(@Log phrase: string) { this.greeting = phrase; } }
以上代码成功运行后,控制台会输出一下结果:```javascript"The parameter in position 0 at Greeter has been decorated"
