01 TypeScript简介
TypeScript是一种由微软开发的编程语言,它是JavaScript的超集,可以编译为纯JavaScript代码。TypeScript添加了静态类型、类、接口和模块等功能,使得开发者可以更加规范和可靠地编写JavaScript代码。它还提供了更好的代码提示和自动补全功能,以及更强大的工具支持。TypeScript可以在任何支持JavaScript的地方运行,并且可以与现有的JavaScript库和框架无缝集成。
02 TypeScript类的基本使用
- 类的定义和声明:
typescripttypescript 复制代码 class Person { private name: string; constructor(name: string) { this.name = name; } sayHello() { console.log(`Hello, my name is ${this.name}.`); } }
在此案例中,定义了一个名为Person的类。它有一个私有属性name和一个构造函数,构造函数接受一个参数name并将其赋值给属性name。类中还有一个名为sayHello的方法,它会在控制台输出一句问候语,包含了属性name的值。
- 属性和方法的定义和访问修饰符:
typescripttypescript 复制代码 class Person { private name: string; protected age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } sayHello() { console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`); } }
在此引入了访问修饰符。私有属性name只能在类内部访问,而受保护属性age可以在类内部和子类中访问。构造函数接受两个参数name和age,将它们分别赋值给对应的属性。
- 类的继承和多态性:
typescripttypescript 复制代码 class Student extends Person { private grade: number; constructor(name: string, age: number, grade: number) { super(name, age); this.grade = grade; } sayHello() { console.log(`Hello, my name is ${this.name}, I'm ${this.age} years old, and I'm in grade ${this.grade}.`); } }
- 抽象类和接口的使用:
typescripttypescript 复制代码 abstract class Shape { abstract getArea(): number; } interface Printable { print(): void; } class Circle extends Shape implements Printable { private radius: number; constructor(radius: number) { super(); this.radius = radius; } getArea() { return Math.PI * this.radius ** 2; } print() { console.log(`The area of the circle is ${this.getArea()}.`); } }
在抽象类Shape定义了一个抽象方法getArea,它没有具体的实现,只是用来约束子类必须实现该方法。接口Printable定义了一个方法print,任何实现该接口的类都必须实现print方法。Circle类继承了Shape抽象类,并实现了Printable接口。它有一个私有属性radius,并实现了getArea和print方法。
03 TypeScript泛型的基本概念
- 泛型的定义和声明:
sqltypescript 复制代码 function identity<T>(arg: T): T { return arg; } let result = identity<string>("Hello TypeScript"); console.log(result);
期望输出:
Hello TypeScript
- 泛型类、泛型函数和泛型接口的使用:
typescripttypescript 复制代码 class Box<T> { private value: T; constructor(value: T) { this.value = value; } getValue(): T { return this.value; } } let box = new Box<number>(10); console.log(box.getValue()); // Output: 10 function printArray<T>(arr: T[]): void { for (let item of arr) { console.log(item); } } printArray<number>([1, 2, 3, 4, 5]); interface Pair<T, U> { first: T; second: U; } let pair: Pair<number, string> = { first: 1, second: "two" };
04 泛型的使用场景与实践
- 在容器类中使用泛型,如数组、集合等:
initypescript 复制代码 function reverse<T>(arr: T[]): T[] { return arr.reverse(); } let reversedArray = reverse<number>([1, 2, 3, 4, 5]); console.log(reversedArray);
期望输出:
[5, 4, 3, 2, 1]
reverse函数接受一个泛型参数arr,它是一个数组,并将数组反转后返回。在调用reverse函数时,我们显式地指定了泛型参数为number类型的数组。
- 在函数中使用泛型,增加函数的通用性
initypescript 复制代码 function mergeArrays<T>(arr1: T[], arr2: T[]): T[] { return [...arr1, ...arr2]; } let mergedArray = mergeArrays<number>([1, 2, 3], [4, 5, 6]); console.log(mergedArray);
期望输出:
[1, 2, 3, 4, 5, 6]
- 在接口中使用泛型,使接口更加灵活
scsstypescript 复制代码 interface Repository<T> { getById(id: number): T; getAll(): T[]; save(item: T): void; update(item: T): void; delete(id: number): void; }
- 在类中使用泛型,提高代码的复用性和可扩展性:
arduinotypescript 复制代码 class Stack<T> { private items: T[] = []; push(item: T): void { this.items.push(item); } pop(): T | undefined { return this.items.pop(); } } let stack = new Stack<number>(); stack.push(1); stack.push(2); stack.push(3); console.log(stack.pop());
期望输出:
3
05 使用类型约束增加代码的灵活性和安全性
- 使用泛型约束,限制泛型的类型范围:
typescripttypescript 复制代码 interface Lengthwise { length: number; } function printLength<T extends Lengthwise>(arg: T): void { console.log(arg.length); } printLength("Hello"); // Output: 5 printLength([1, 2, 3, 4, 5]); // Output: 5
- 使用关键字"extends"进行类型约束:
initypescript 复制代码 function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } let person = { name: "Alice", age: 30 }; let name = getProperty(person, "name"); console.log(name);
期望输出:
Alice
- 通过类型约束避免运行时错误和类型错误:
typescripttypescript 复制代码 function safeParseJson<T>(jsonString: string): T | null { try { return JSON.parse(jsonString) as T; } catch (e) { console.error("Invalid JSON string:", e); return null; } } let parsedData = safeParseJson<{ name: string }>('{"name": "Alice"}'); if (parsedData) { console.log(parsedData.name); }
期望输出:
Alice
此代码中safeParseJson函数接受一个泛型参数T和一个字符串jsonString,它尝试将jsonString解析为类型T,并返回解析后的结果。在try块中,我们使用as操作符将解析结果断言为类型T。如果解析成功,函数返回解析结果;否则,函数捕获错误并返回null。在调用safeParseJson函数时,在此显式地指定了泛型参数为一个包含name属性的对象类型,所以函数能够正确解析并返回相应的数据。
06 总结
通过TypeScript的类和泛型特性,可以在代码中实现更高的灵活性和安全性。类的继承、多态性、抽象类和接口使得代码更加模块化和可复用,而泛型的使用则增加了代码的通用性和可扩展性。通过使用类型约束,我们可以避免运行时错误和类型错误,提高代码的可维护性。因此,在TypeScript中合理地使用类和泛型,并加以类型约束,有助于提高代码的质量和开发效率。