TypeScript基础 | 青训营笔记

74 阅读3分钟

背景

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接口中定义的两个方法:flyrestockFuelfly方法只是打印一个字符串,restockFuel方法更新了飞船的燃料值。

然后创建一个名为ship的实例对象,它是Ship接口的类型,并即为CargoShip类的一个实例。最后,在这个实例上调用flyrestockFuel方法。

此练习展示了如何使用接口、类和实现多态的基础知识,以及在TypeScript中如何定义和使用它们。