Typescript高级教程(一)
简介
在这篇文章中,我们会讲解一些 Typescript 的高级用法以及一些常见的应用场景,包括:
- 泛型
- 类型别名与接口
- 类型守卫
- 高级类型
- 装饰器
泛型
泛型是指在定义函数、接口或者类时,使用一个占位符表示某个类型,从而实现代码的重用性和类型的灵活性。
泛型函数
泛型函数可以接受任意类型的参数,并且可以在函数内部使用泛型来处理参数,例如:
function identity<T>(arg: T): T {
return arg;
}
// 使用泛型函数
console.log(identity<string>('hello')); // 输出 hello
console.log(identity<number>(123)); // 输出 123
在上面的示例中,identity
函数使用了一个类型参数 T
,表示传入的参数类型和函数返回值类型相同。实际使用时,可以通过指定类型参数的方式来调用这个函数。
泛型接口
泛型接口可以更加灵活地定义对象的类型,例如:
interface Pair<T, U> {
first: T;
second: U;
}
// 使用泛型接口
let pair: Pair<string, number> = { first: 'one', second: 1 };
console.log(pair.first); // 输出 one
console.log(pair.second); // 输出 1
在上面的示例中,Pair
接口使用了两个类型参数 T
和 U
来表示对象中属性的类型。实际使用时,可以通过指定类型参数的方式来定义对象的类型。
类型别名与接口
类型别名和接口可以用来定义复杂的类型,例如:
type Person = {
name: string;
age: number;
getAddress(): string;
}
interface Animal {
name: string;
age: number;
readonly gender: string;
getAge(): number;
}
// 使用类型别名和接口定义一个函数
function printInfo(obj: Person | Animal) {
// ...
}
在上面的示例中,我们使用了类型别名 Person
和接口 Animal
来定义对象的类型。这些类型可以用来定义函数参数或者返回值的类型,并且可以通过类型交叉和联合的方式进行组合。
类型守卫
类型守卫可以用来在运行时判断一个变量的类型,并且进行相应的处理。例如:
class Cat {
meow() {
console.log('meow');
}
}
class Dog {
bark() {
console.log('bark');
}
}
function makeSound(animal: Cat | Dog) {
if ('meow' in animal) {
// animal 是 Cat 类型
animal.meow();
} else {
// animal 是 Dog 类型
animal.bark();
}
}
在上面的示例中,我们使用了 in 操作符来判断变量的类型,并且执行相应的操作。类型守卫还可以使用 typeof、instanceof、null、undefined、boolean、number、string
等操作符进行判断。
高级类型
Typescript 提供了一些高级类型,可以用来描述函数的参数和返回值类型、表达式的属性类型、数组和元祖的扩展操作等。
函数类型
函数类型可以用来描述函数的参数和返回值类型,例如:
type Func = (a: number, b: string) => boolean;
const add: Func = (a, b) => {
return true;
}
在上面的示例中,我们使用了函数类型 Func
来描述函数参数和返回值的类型,在实际使用时可以通过 Func
来声明一个函数。
属性访问类型
属性访问类型可以用来表示对象中某个属性的类型,例如:
type PersonProps = {
name: string;
age: number;
}
type NameType = PersonProps['name']; // string
在上面的示例中,我们使用了属性访问类型 PersonProps['name']
来表示 PersonProps
对象中 name 属性的类型。
数组操作类型
数组操作类型可以用来实现数组的扩展和操作,例如:
type First<T extends any[]> = T extends [infer F, ...any[]] ? F : never;
type Arr = ["foo", 42, true];
type Head = First<Arr>; // "foo"
在上面的示例中,我们使用了数组操作类型 First 来获取一个数组的第一个元素。这里使用了 Type Script
中的特殊语法,类似于结构体的形式。
装饰器
装饰器可以用来给类和类成员添加元数据或者修改行为。装饰器可以用来实现日志记录、权限控制、性能分析等功能。
类装饰器
类装饰器可以用来添加类的元数据或者修改类的行为,例如:
function addAge<T extends { new(...args: any[]): {} }>(constructor: T) {
return class extends constructor {
age: number = 18;
}
}
@addAge
class Person {
name: string = 'Tom';
}
console.log(new Person()); // 返回 { name: 'Tom', age: 18 }
在上面的示例中,我们使用了类装饰器 addAge
来给 Person
类添加了一个 age 属性,并且修改了 Person
类的行为。
方法装饰器
方法装饰器可以用来修改类中的方法行为,例如:
function log(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {
let originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${ propertyKey } with arguments: ${ JSON.stringify(args) }`);
return originalMethod.apply(this, args);
};
return descriptor;
}
class MyClass {
@log
method(a: number, b: string) {
console.log(`Hello ${ b }`);
}
}
let myClass = new MyClass();
myClass.method(123, 'world');
在上面的示例中,我们使用了方法装饰器 log
来添加日志记录功能,在调用 MyClass.method
方法时,会打印函数名和参数列表,并且返回原始方法的调用结果。
总结
到这里,我们已经讲解了 Typescript 的一些高级用法和常见应用场景,涵盖了泛型、类型别名与接口、类型守卫、高级类型和装饰器等。希望这篇文章对各位 Typescript 开发者有帮助,也欢迎大家提出宝贵意见。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。