深入浅出TypeScript | 青训营笔记

92 阅读7分钟

深入浅出TypeScript

1. 为什么要学TypeScript

它是一种静态类型的编程语言,它是 JavaScript 的超集,可以让代码更加可读、可维护和可扩展。以下是学习 TypeScript 的一些好处:

  1. 更好的代码可读性:TypeScript 强制类型约束,可以让代码更加清晰易懂,减少了代码出错的可能性。
  2. 更好的代码维护性:TypeScript 提供了更好的代码提示和错误提示功能,可以帮助开发者更快地定位和修复代码中的问题。
  3. 更好的代码扩展性:TypeScript 支持面向对象编程,可以让代码更加模块化和可扩展。
  4. 更好的团队协作:TypeScript 可以让多个开发者在同一个项目中协作开发,减少了代码冲突和错误的可能性。
  5. 更好的工具支持:TypeScript 可以与许多流行的编辑器和开发工具集成,如 Visual Studio Code、WebStorm 等,可以提高开发效率。

总之,学习 TypeScript 可以让开发者写出更加健壮、可维护和可扩展的代码,提高开发效率和团队协作能力。

2. TS基础

2.1 TS基础类型

TypeScript 的基础类型包括以下几种:

  1. Boolean 类型:表示布尔值,只能取 true 或 false。
  2. Number 类型:表示数字,包括整数和浮点数。
  3. String 类型:表示字符串,包括单引号和双引号。
  4. Array 类型:表示数组,可以包含任意类型的元素。
  5. Tuple 类型:表示元组,可以包含固定数量和类型的元素。
  6. Enum 类型:表示枚举,可以用于定义一组有限的命名常量。
  7. Any 类型:表示任意类型,可以用于定义不确定类型的变量。
  8. Void 类型:表示没有返回值的函数。
  9. Null 和 Undefined 类型:表示 null 和 undefined 值。
  10. Never 类型:表示永远不会返回结果的函数。

以上是 TypeScript 的基础类型,掌握这些类型可以让开发者更加灵活地定义变量和函数,并提高代码的可读性和可维护性。

image.png
2.2 TS函数类型

TypeScript 中的函数类型包括以下几种:

  1. 函数声明类型:使用 function 关键字定义函数时,可以指定函数的参数类型和返回值类型。
function add(x: number, y: number): number {
  return x + y;
}
  1. 函数表达式类型:使用箭头函数或匿名函数定义函数时,可以使用类型注解指定参数类型和返回值类型。
let add: (x: number, y: number) => number = function(x, y) {
  return x + y;
};
  1. 接口类型:使用接口定义函数类型时,可以指定函数的参数类型和返回值类型。
interface AddFunction {
  (x: number, y: number): number;
}

let add: AddFunction = function(x, y) {
  return x + y;
};
  1. 类型别名类型:使用类型别名定义函数类型时,可以指定函数的参数类型和返回值类型。
type AddFunction = (x: number, y: number) => number;

let add: AddFunction = function(x, y) {
  return x + y;
};

image.png

2.3 interface

在 TypeScript 中,interface 是一种定义对象类型的方式,它可以用于描述对象的属性、方法和索引类型等信息。interface 的作用是规范代码的结构,提高代码的可读性和可维护性。

interface 的特点如下:

  1. 可以定义对象的属性和方法:使用 interface 可以定义对象的属性和方法,包括属性的类型和方法的参数和返回值类型等信息。
  2. 可以定义可选属性和只读属性:使用 ? 符号可以定义可选属性,使用 readonly 关键字可以定义只读属性。
  3. 可以定义索引类型:使用 [propName: string] 或 [index: number] 等形式可以定义索引类型。
  4. 可以继承其他接口:使用 extends 关键字可以继承其他接口的属性和方法。
  5. 可以定义函数类型:使用 interface 可以定义函数类型,包括函数的参数和返回值类型等信息。
  6. 可以定义类类型:使用 interface 可以定义类类型,包括类的属性和方法等信息。

以下是 TypeScript 中 interface 的一些示例:

  1. 定义对象类型
interface Person {
  name: string;
  age: number;
  gender: string;
}

let person: Person = {
  name: "张三",
  age: 18,
  gender: "男"
};
  1. 定义函数类型
interface AddFunction {
  (x: number, y: number): number;
}

let add: AddFunction = function(x, y) {
  return x + y;
};
  1. 定义可选属性和只读属性
interface Person {
  name: string;
  age?: number; // 可选属性
  readonly id: number; // 只读属性
}

let person: Person = {
  name: "张三",
  id: 1
};
  1. 继承其他接口
interface Animal {
  type: string;
}

interface Cat extends Animal {
  name: string;
  age: number;
}

let cat: Cat = {
  type: "猫科动物",
  name: "小猫",
  age: 1
};
  1. 索引类型
interface StringArray {
  [index: number]: string;
}

let arr: StringArray = ["a", "b", "c"];

以上是 TypeScript 中 interface 的一些示例,可以根据实际需求选择不同的方式来定义 interface。interface 的定义可以帮助开发者更加清晰地理解对象的结构和特性,并提高代码的可读性和可维护性。

image.png image.png
2.4 类
  • 与js差不多 在 TypeScript 中,类是一种定义对象模板的方式,它可以用于封装数据和行为,并提供了继承和多态等特性。以下是 TypeScript 中类的使用举例:
  1. 定义类
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}, I'm ${this.age} years old.`);
  }
}

let person = new Person("张三", 18);
person.sayHello(); // Hello, my name is 张三, I'm 18 years old.
  1. 继承类
class Student extends Person {
  grade: number;

  constructor(name: string, age: number, grade: number) {
    super(name, age);
    this.grade = grade;
  }

  study() {
    console.log(`${this.name} is studying in grade ${this.grade}.`);
  }
}

let student = new Student("李四", 20, 3);
student.sayHello(); // Hello, my name is 李四, I'm 20 years old.
student.study(); // 李四 is studying in grade 3.
  1. 类的访问修饰符
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}, I'm ${this.age} years old.`);
  }
}

class Student extends Person {
  private grade: number;

  constructor(name: string, age: number, grade: number) {
    super(name, age);
    this.grade = grade;
  }

  study() {
    console.log(`${this.name} is studying in grade ${this.grade}.`);
  }
}

let person = new Person("张三", 18);
console.log(person.name); // Error: 'name' is private and only accessible within class 'Person'.
console.log(person.age); // OK

let student = new Student("李四", 20, 3);
console.log(student.age); // OK
console.log(student.grade); // OK
console.log(student.name); // Error: 'name' is private and only accessible within class 'Person'.
  1. 类的静态属性和方法
class Person {
  static count: number = 0;

  constructor() {
    Person.count++;
  }

  static getCount() {
    console.log(`There are ${Person.count} persons.`);
  }
}

let p1 = new Person();
let p2 = new Person();
Person.getCount(); // There are 2 persons.

image.png

3. TS进阶

3.1 高级类型

在 TypeScript 中,高级类型是指一些比基础类型更加复杂的类型,包括联合类型、交叉类型、类型别名、泛型等。以下是 TypeScript 中高级类型的说明及举例:

  1. 联合类型

联合类型表示一个值可以是多种类型之一,使用 | 分割类型。

let value: string | number;

value = "hello"; // OK
value = 123; // OK
value = true; // Error: Type 'boolean' is not assignable to type 'string | number'.
  1. 交叉类型

交叉类型表示将多个类型合并为一个类型,使用 & 分割类型。

interface A {
  a: string;
}

interface B {
  b: number;
}

let value: A & B = {
  a: "hello",
  b: 123
};
  1. 类型别名

类型别名可以给一个类型起一个新的名字,方便后续使用。

type MyString = string;

let str: MyString = "hello";
  1. 泛型

泛型可以让一个函数或类适用于多种类型,增加代码的灵活性和复用性。

function identity<T>(arg: T): T {
  return arg;
}

let str = identity<string>("hello");
let num = identity<number>(123);

image.png

以上是 TypeScript 中一些高级类型的说明及举例,这些高级类型可以帮助开发者更加灵活地处理复杂的数据类型和数据结构,提高代码的可读性和可维护性。

3.2 泛型工具类型之基础操作符

image.png

image.png

3.3 泛型常用工具类型

image.png

4. 实战&工程项

4.1 声明文件

image.png

4.2 泛型约束后端类型

泛型约束后端类型是指在使用泛型时,限制泛型类型必须是某种特定类型或满足某种特定条件,以提高代码的类型安全性和可读性。

以下是一个示例,使用泛型约束后端类型:

interface User {
  id: number;
  name: string;
  age: number;
}

function getUser<T extends User>(users: T[], id: number): T | undefined {
  return users.find(user => user.id === id);
}

const users: User[] = [
  { id: 1, name: "张三", age: 18 },
  { id: 2, name: "李四", age: 20 },
  { id: 3, name: "王五", age: 22 }
];

const user = getUser(users, 2);

console.log(user?.name); // 输出:李四

在上面的代码中,getUser 函数使用泛型约束类型 T 必须是 User 类型或 User 类型的子类型,这样就可以保证函数返回的结果类型是正确的。

在实际开发中,泛型约束后端类型可以帮助开发者更好地控制代码的类型,避免类型错误和运行时错误,提高代码的可靠性和可维护性。

image.png