TypeScript类、泛型的使用实践记录
TypeScript类
类是面向对象编程的基本概念,它是一种将数据和方法封装在一起的结构。在Typescript中,可以使用class关键字定义一个类,并在类中定义属性和方法。类可以继承其他类,并且可以实现接口。通过类的实例化,可以创建对象并调用对象的方法。
基本用法
下面为大家举一个类的例子:
class Person {
// 定义类的属性
name: string;
age: number;
// 定义类的构造函数
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 定义类的方法
sayHello() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
上面的示例中,我们定义了一个名为Person的类。它有两个属性:name和age,以及一个构造函数用于初始化这些属性。还有一个名为sayHello的方法,用于打印一条问候消息。
类的调用
要使用这个类,我们可以创建一个类的实例并调用它的方法,如下所示:
const person = new Person("John", 25);
person.sayHello(); // 输出:Hello, my name is John and I am 25 years old.
在这个示例中,我们创建了一个名为person的Person类的实例,并调用了它的sayHello方法。
类的继承
类还支持继承,可以通过extends关键字来实现。例如,我们可以创建一个Student类来继承Person类的属性和方法:
class Student extends Person {
// 定义新的属性
studentId: number;
// 定义新的构造函数
constructor(name: string, age: number, studentId: number) {
super(name, age); // 调用父类的构造函数
this.studentId = studentId;
}
// 重写父类的方法
sayHello() {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old, and my student ID is ${this.studentId}.`);
}
}
在这个示例中,我们创建了一个名为Student的类,它继承了Person类的属性和方法,并添加了一个新的属性studentId和一个重写的sayHello方法。在构造函数中,我们使用super关键字调用父类的构造函数来初始化继承的属性。然后,我们重写了父类的sayHello方法,添加了学生ID的输出。
我们可以像使用Person类一样使用Student类:
const student = new Student("Alice", 20, 123456);
student.sayHello(); // 输出:Hello, my name is Alice, I am 20 years old, and my student ID is 123456.
在这个示例中,我们创建了一个名为student的Student类的实例,并调用了它的sayHello方法,输出了一个带有学生ID的问候消息。
通过类的继承,我们可以构建更复杂的类层次结构,并重用已有类的属性和方法。这使得代码更可维护、可扩展和可重用。
公共,私有与受保护的修饰符
在TypeScript中,类的属性和方法可以使用不同的访问修饰符来控制其可见性和访问级别。这些修饰符包括公共(public)、私有(private)和受保护(protected)。
- 公共(public)修饰符可以应用于类的属性和方法,表示它们可以在任何地方被访问。如果没有指定修饰符,默认为公共修饰符。例如:
class MyClass {
public publicProperty: string;
public publicMethod(): void {
// 公共方法的实现
}
}
在类的外部,可以通过实例对象访问公共成员:
const obj = new MyClass();
obj.publicProperty = 'Hello';
obj.publicMethod();
- 私有(private)修饰符可以应用于类的属性和方法,表示它们只能在类的内部被访问。例如:
class MyClass {
private privateProperty: string;
private privateMethod(): void {
// 私有方法的实现
}
}
在类的外部,无法直接访问私有成员:
const obj = new MyClass();
obj.privateProperty; // 无法访问私有成员
obj.privateMethod(); // 无法访问私有成员
- 受保护(protected)修饰符可以应用于类的属性和方法,表示它们只能在类的内部和派生类中被访问。派生类是指通过继承关系从该类派生出来的子类。例如:
class MyBaseClass {
protected protectedProperty: string;
protected protectedMethod(): void {
// 受保护方法的实现
}
}
class MyDerivedClass extends MyBaseClass {
public accessProtected(): void {
this.protectedProperty = 'Hello'; // 可以在派生类中访问受保护成员
this.protectedMethod(); // 可以在派生类中访问受保护成员
}
}
在类的外部,无法直接访问受保护成员:
const obj = new MyBaseClass();
obj.protectedProperty; // 无法访问受保护成员
obj.protectedMethod(); // 无法访问受保护成员
总结:
- 公共成员可以在类的内部和外部访问。
- 私有成员只能在类的内部访问。
- 受保护成员可以在类的内部和派生类中访问,但无法在类的外部访问。
TypeScript泛型
泛型是一种在编程中使用类型参数的技术,它可以在定义函数、类或接口时使用类型变量来代替具体的类型。通过使用泛型,可以增加代码的灵活性和重用性。在Typescript中,可以使用尖括号<>来声明泛型,并在函数或类中使用泛型变量。
泛型的使用方法
在TypeScript中,泛型可以应用于函数、类和接口等各种场景。
函数中的泛型
-
可以在函数定义时使用泛型来表示参数的类型,从而增加函数的灵活性。例如:
function identity<T>(arg: T): T { return arg; }
-
可以在函数调用时指定具体的类型参数,从而限制参数的类型。例如:
let result = identity<string>("hello");
类中的泛型
-
可以在类定义时使用泛型来表示类的成员的类型。例如:
class Box<T> { private value: T; constructor(value: T) { this.value = value; } getValue(): T { return this.value; } }
-
可以在创建类的实例时指定具体的类型参数。例如:
let box = new Box<number>(10);
接口中的泛型
-
可以在接口定义时使用泛型来表示接口的成员的类型。例如:
interface Pair<T, U> { first: T; second: U; }
-
可以在实现接口时指定具体的类型参数。例如:
let pair: Pair<number, string> = { first: 1, second: "two" };
TypeScript中泛型的使用场景
泛型的使用场景包括但不限于以下几种:
- 提供类型安全的参数和返回值,避免类型错误。
- 增加代码的重用性,可以在不同的地方使用相同的逻辑和类型。
- 支持不同类型的参数,提供更灵活的接口。
- 在容器类中使用泛型可以提供类型安全的数据存储和检索。
- 在函数式编程中,泛型可以用于定义高阶函数和函数组合等功能。
泛型的使用可以大大提高代码的可重用性和类型安全性,特别是在处理集合、函数式编程和异步编程等场景中非常有用。
使用类型约束来增加代码的灵活性和安全性
在TypeScript中,可以使用类型约束来增加代码的灵活性和安全性。
使用类型注解
-
可以使用类型注解来明确函数参数和返回值的类型,从而增加代码的安全性。例如:
function add(a: number, b: number): number { return a + b; }
使用泛型
- 可以使用泛型来增加函数、类和接口的灵活性。通过泛型,可以在定义时不指定具体的类型,而是在使用时动态指定类型。例如:
function identity<T>(arg: T): T {
return arg;
}
使用类型别名和接口
- 可以使用类型别名和接口来定义复杂的类型约束,从而增加代码的灵活性和可读性。例如:
type Point = {
x: number;
y: number;
};
interface Shape {
color: string;
area(): number;
}
使用类型守卫
- 可以使用类型守卫来在运行时检查变量的类型,从而增加代码的安全性。类型守卫可以使用
typeof
、instanceof
、in
等运算符进行类型检查。例如:
function printValue(value: string | number) {
if (typeof value === "string") {
console.log(value.toUpperCase());
} else if (typeof value === "number") {
console.log(value.toFixed(2));
}
}
使用非空断言
- 可以使用非空断言(
!
)来告诉编译器某个变量一定不为null
或undefined
,从而增加代码的安全性。例如:
function printLength(str: string | null) {
console.log(str!.length);
}
通过使用类型约束,可以在编写代码时提供更多的类型信息,从而增加代码的灵活性和安全性。类型约束可以帮助开发者在编译时捕获潜在的类型错误,并提供更好的代码提示和自动补全功能。