背景
TypeScript是一种由Microsoft开发和维护的强类型(静态类型)JavaScript超集。它添加了类、接口、类型注释等功能,并通过静态类型检查来提供更好的编辑器支持、代码可读性和可维护性。TypeScript最初发布于2012年,自推出以来已经得到了各种方面的推广和采用。
优缺点
优点
- 强类型检查器提供了良好的编译时错误检查和类型推断,可以更早地发现和解决代码问题。
- 可以提高代码可读性和可维护性,使代码更加健壮、可靠。
- 更好的现代语言特性支持,例如类、接口、高阶函数、枚举等等,易于构建可维护、可扩展的大型应用程序。
- TypeScript可以编译成标准的JavaScript,从而可以在任何支持JavaScript的浏览器或环境中运行。
缺点
- 初学成本较高,需要花费时间学习新的语言特性和类型系统。
- 微型项目可能不需要这么多附加功能,引用TypeScript的代价可能比较高。
- 需要引入新的技术栈,需要对TypeScript的工具链以及周边生态有更多的了解。
社区活跃度
TypeScript的使用呈上升趋势,是目前最受欢迎的构建大型应用程序的语言之一。据GitHub的开源社区,TypeScript在2019年超越了Ruby和C#,成为了第四大使用语言。TypeScript拥有强大的社区支持,除了微软之外,也有很多贡献者和开发人员为其开发和维护工作做出贡献。
常用类型基本概念
基础类型
TypeScript中的基础类型与JavaScript非常相似,包括Boolean、Number、String、Array、Object、Null、Undefined、Symbol等类型。还有一些特殊的类型,例如Any、Void和Never。
let isActive: boolean = true;
let age: number = 30;
let username: string = "John";
let hobbies: string[] = ['reading', 'swimming'];
let person: object = { name: 'John', age: 30 };
let nothing: null = null;
let unknown: any = 'hello';
let empty: void = undefined;
let never: never = (() => { throw Error('Oops')})();
对象类型
对象类型可以由接口Interface或类Class来表示。接口描述了对象的规范,类描述了对象的特征和行为。
interface Person {
name: string;
age: number;
}
class Employee {
readonly id: number;
name: string;
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
getDetails() {
return {
id: this.id,
name: this.name
}
}
}
let person: Person = { name: 'John', age: 30 };
let employee: Employee = new Employee(1, 'Alex');
接口
接口定义了类、函数、对象等的类型。接口描述将有哪些属性以及属性的类型、函数参数的类型和返回类型。
interface Person {
name: string;
age: number;
}
function printPerson(person: Person) {
console.log(`Name: ${person.name}, Age: ${person.age}`);
}
断言
类型断言可以在编译时的类型检查中覆盖编译器的类型推断。使用类型转换运算符来指定变量的类型。
let someValue: unknown = 'hello world';
let strLength: number = (someValue as string).length
进阶用法
类
类是JavaScript中常用的一种面向对象的封装方式。TypeScript中的类增加了许多新功能,例如成员修饰符、构造函数、继承等。
class Person {
protected name: string;
constructor(name: string) {
this.name = name;
}
sayHello() {
console.log(`Hello, my name is ${this.name}.`);
}
}
let person: Person = new Person('John');
person.sayHello(); // 输出:Hello, my name is John.
泛型
泛型可以用于编写可重用和类型安全的代码,支持任何类型的数据作为参数,并可以正确地处理不同类型的数据。
function identity<T>(arg: T): T {
return arg;
}
let output1: string = identity<string>("hello");
let output2: number = identity<number>(1);
工程逆向
代码检测
TypeScript可以在编译时进行类型检查,但编译器并不是万无一失的。——需要使用第三方的工具,例如TsLint和ESLint,来执行代码检测。
编译配置
TypeScript编译器的行为可以在tsconfig.json文件中进行配置。该文件指定了TypeScript项目的根目录、编译输出目录、代码库中要包含的文件和文件夹、代码库要排除的文件和文件夹,以及其他编译器选项。
工程中最佳实践
下面是一些TypeScript工程中的最佳实践:
- 始终使用类型标注和强类型检查
- 避免使用any类型,使用泛型或联合类型来代替
- 确保代码符合一致的编程风格和公司规定的最佳实践
- 使用相对导入,对文件系统的影响更小
- 使用webpack、gulp或Rollup等构建工具来构建应用程序
迁移工具
对于已有的JavaScript项目,可以使用TypeScript的迁移工具,例如全局替换工具(TypeScript migration tool)和自动类型推导工具(ts-migrate),使项目更容易地从JavaScript迁移到TypeScript。
小练习
interface Ship {
name: string;
cargo: string[];
crew: number;
captain: string;
fuel: number;
fly(): void;
restockFuel(fuel: number): void;
}
class CargoShip implements Ship {
constructor(
public name: string,
public cargo: string[],
public crew: number,
public captain: string,
public fuel: number
) {}
fly(): void {
console.log(`${this.name} cannot fly!`);
}
restockFuel(fuel: number): void {
this.fuel = fuel;
}
}
const ship: Ship = new CargoShip('Black Pearl', ['gold'], 20, 'Jack Sparrow', 100);
ship.fly(); // 输出:Black Pearl cannot fly!
ship.restockFuel(200);
这段代码定义了一个接口Ship和一个实现这个接口的类CargoShip。这个类有一个构造方法来初始化类的属性,还实现了Ship接口中定义的两个方法:fly和restockFuel。fly方法只是打印一个字符串,restockFuel方法更新了飞船的燃料值。
然后创建一个名为ship的实例对象,它是Ship接口的类型,并即为CargoShip类的一个实例。最后,在这个实例上调用fly和restockFuel方法。
此练习展示了如何使用接口、类和实现多态的基础知识,以及在TypeScript中如何定义和使用它们。