背景

Typescript 是一种由微软开发的自由与开源的编程语言。
TypeScript 设计目标是开发大型应用,然后转译成 JavaScript。
由于 TypeScript 是 JavaScript 的严格超集,任何现有的 JavaScript 程序都是合法的 TypeScript 程序。
目前有很多大型开源项目都开始使用 TypeScript,例如:Vue 3.0、React 周边、Angluar、Vscode、AntDesign、Taro 等。

安装

npm

首先,在命令行运行 npm install -g typescript 命令全局安装 typescript;
其次,在命令行通过 tsc 命令执行 typescript 相关文件;
举例:新建一个 test.ts 文件,通过在命令行运行 tsc test.ts,同一个目录下会生成一个 test.js 文件。

  1. tsc test.ts

编辑器

例如:Vscode、sublime、webstorm 等,都有 TypeScript 插件;
通过这些 IDE 即可自动解析 .ts 文件。

用法

基础类型

  • Boolean(布尔值)
  • Number(数字)
  • String(字符串)
  • Null 与 undefined
  • Object(除 boolean、number、string、symbol、undefined、null 的类型)
  • Any(任何类型)
  • Void(没有任何类型,通常表示无返回值的函数)
  • Never(永远不存在的值类型,是任何类型的子类型,应用场景:无限循环 & 抛出异常)
  • Array (数组)
  • 元组(已知类型和数量的数组)
  • 枚举(对标准数据的类型的补充)
  1. // 布尔值
  2. const sign: boolean = true;
  3. // 数字
  4. const age: number = 6;
  5. // 字符串
  6. const str: string = 'DR';
  7. // undefined、null
  8. const a: undefined = undefined;
  9. const b: null = null;
  10. // object
  11. const obj: object = {};
  12. // any
  13. const age: any = '18';
  14. // void
  15. function eat(): void {}
  16. // never
  17. function drink(): never { while(true) {}; }
  18. function drink(): never { throw new Error(''); }
  19. // 数组
  20. const list: number[] = [1, 2, 3];
  21. const list: Array<number> = [1, 2, 3];
  22. // 元组
  23. const list: [number, string] = [1, 'DR'];
  24. // 枚举
  25. enum Step = { One, Two, Three }; // One = 0, Two = 1, Three = 2
  26. enum Step = { One = 1, Two, Three }; // One = 1, Two = 2, Three = 3

类型断言

可以用来手动指定一个值的类型;
存在两种语法:<类型>值(str)或 值 as 类型(str as string)

  1. // 当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候
  2. // 我们只能访问此联合类型的共有属性或者方法,否则会出现报错
  3. // 可以
  4. getLen = (something: string|number) => {
  5. return something.toString();
  6. }
  7. // 报错
  8. getLen = (something: string|number) => {
  9. return something.length;
  10. }
  11. // 解法,在某些场景下将 something 断言成 string
  12. getLen = (something: string|number) => {
  13. if ((<string>something).length) {
  14. return (<string>something).length;
  15. } else {
  16. return something.toString().length;
  17. }
  18. }

接口

接口是一种规范的定义,它定义了行为和动作的规范,接口起到一种限制和规范的作用;
枚举下接口包含的几种类型:

  • 属性类型接口
  • 函数类型接口
  • 可索引类型接口
  • 类类型接口

    属性类型接口

    对对象进行约束,对象的 Key 与 Value 要遵守接口所声明的内容;
    其中包含:正常属性,可选属性、只读属性等一些特殊内容; ```typescript interface People { name: string; age?: number; // 可选属性 readonly sex: string; // 只读属性 };

const people: People = { name: ‘段然’ // 生命属性,一定要有 age: 18, // 可选属性,可有可无 sex: ‘男’ // 只读属性 };

people.sex = ‘女’; // 错误,只读属性不能修改 console.log(people.sex) // 正确

  1. <a name="2Wa34"></a>
  2. ### 函数类型接口
  3. 对方法传入的参数以及返回值进行约束,函数的参数与返回值要遵守接口所声明的内容;
  4. ```typescript
  5. interface People {
  6. (name: string, age: number): string;
  7. }
  8. const people: People = (name: string, age: number): string => name + age;
  9. people('段然', 18); // 正确
  10. people('段然', '18'); // 错误

可索引类型接口

对数组和对象进行约束(不常用),数组或者对象的索引(数组即下标、对象即 Key)与内容要遵守接口所声明的内容;

  1. interface Obj {
  2. [index: string]: string;
  3. };
  4. interface Arr {
  5. [index: number]: number;
  6. };
  7. const arr1: Arr = [1, 2, 3] // 正确
  8. const arr2: Arr = ['1', '2', '3'] // 错误
  9. const obj1: Obj = { '1': '1' } // 正确
  10. const obj2: Obj = { '1': 1 } // 错误
  11. const obj3: Obj = { 1: 1 } // 错误

类类型接口

对类进行约束,类需要去实现接口中的方法与属性,类的实现要遵守接口所声明的内容;

  1. interface Animal {
  2. name: string;
  3. eat(): void;
  4. };
  5. class Dog implements Animal {
  6. name: string;
  7. constructor() {
  8. this.name = 'dog'
  9. }
  10. eat(): void {
  11. }
  12. };
  13. const dog = new Dog(); // 正确

接口间的继承

接口之间也可以相互继承,如果继承多个接口通过 “,” 分割;

  1. interface A {
  2. name: string;
  3. };
  4. interface B {
  5. age: number;
  6. };
  7. inferface C extends A { // 包含 name: string 与 sex: string
  8. sex: string;
  9. };
  10. inferface D extends A, B { // 包含 name: string、age: number 与 sex: string
  11. sex: string;
  12. };

混合类型接口

混合类型的接口可以混合属性类型接口与函数类型接口;

  1. interface Person {
  2. (name: string, age: number): string; // 函数类型接口;
  3. eat(): void; // 属性类型接口
  4. }
  5. function person: Person {
  6. // 函数类型接口应用
  7. const p: Person = (name: string, age: number): string => name + age;
  8. // 属性类型接口
  9. p.eat = () => {};
  10. return p;
  11. }
  12. const p = person();
  13. p('段然', 18); // 正确
  14. p.eat(); // 正确

接口继承类

接口继承了一个类时,它会继承类的成员但不包括其实现(会继承到类的 private、protected、public 成员);

  1. class A {
  2. name: string;
  3. constructor() {
  4. this.name = '段然';
  5. }
  6. }
  7. interface B extends A {
  8. age: number;
  9. } // 此时 B 接口中存在 name: string 与 age: number 两个属性
  10. class C implements B {
  11. name: string;
  12. age: number;
  13. constructor() {
  14. // 类 C 必须要实现接口 B 包含的成员(name 与 age)
  15. this.name = '段然';
  16. this.age = 18;
  17. }
  18. }
  19. class D extends A implements B {
  20. age: number;
  21. constructor() {
  22. // 类 D 必须要实现接口 B 包含的成员(name 与 age)
  23. // 但由于继承自 A,已经包含了 name,只实现 age 即可
  24. this.age = 18;
  25. }
  26. }

公共、受保护与私有修饰符

  • public 公共修饰符,Typescript 中默认为 public
    • 类的实例可使用类中的方法与属性
    • 派生的类可使用类中的方法与属性 ```javascript class A { public name: string; public constructor(): void { this.name = ‘段然’ } public say(): void { console.log(this.name); } }

class B extends A { constructor(props) { super(props); this.say(); // 正确 } }

const a = new A(); a.name = ‘段然然’; // 正确 a.say(); // 正确

  1. - protected 受保护修饰符
  2. - 类的实例不可使用类中的方法与属性
  3. - 派生的类可使用类中的方法与属性
  4. ```javascript
  5. class A {
  6. protected name: string;
  7. protected constructor(): void {
  8. this.name = '段然'
  9. }
  10. protected say(): void {
  11. console.log(this.name);
  12. }
  13. }
  14. class B extends A {
  15. constructor(props) {
  16. super(props);
  17. this.say(); // 正确
  18. }
  19. }
  20. const a = new A();
  21. a.name = '段然然'; // 错误,类的实例不可使用类中的方法与属性
  22. a.say(); // 错误,类的实例不可使用类中的方法与属性
  • private 私有修饰符
    • 类的实例不可使用类中的方法与属性
    • 派生的类不可使用类中的方法与属性 ```javascript class A { private name: string; private constructor(): void { this.name = ‘段然’ } private say(): void { console.log(this.name); } }

class B extends A { constructor(props) { super(props); this.say(); // 错误,派生的类不可使用类中的方法与属性 } }

const a = new A(); a.name = ‘段然然’; // 错误,类的实例不可使用类中的方法与属性 a.say(); // 错误,类的实例不可使用类中的方法与属性

  1. <a name="LHNn7"></a>
  2. ### 只读属性
  3. 通过 readonly 修饰符可以设置类的属性为只读属性;
  4. ```javascript
  5. class A {
  6. public readonly name: string;
  7. public constructor(): void {
  8. this.name = '段然'
  9. }
  10. }
  11. const a = new A();
  12. a.name = '段然然'; // 报错,属性只读,不可修改
  13. console.log(a.name) // 正确

静态属性

通过 static 修饰符可以设置属性与方法为静态属性,static 设置的属性与方法是挂载在类上面的,类的实例上是不存在此属性与方法的;

  1. class A {
  2. static name = '段然';
  3. static say () {
  4. console.log(A.name);
  5. }
  6. };
  7. console.log(A.name); // 正确
  8. A.say(); // 正确

抽象类

抽象类可以做为其它派生类的基类使用,它们不可以被实例化;

  1. abstract class A {
  2. public readonly name: string;
  3. public constructor(): void {
  4. this.name = '段然'
  5. }
  6. }
  7. class B extends A {} // 正确
  8. const a = new A(); // 报错

函数

为函数定义类型

Typescript 中的函数可以定义参数类型与返回类型;

  1. function people (name: string): void {}
  2. people('段然'); // 接收的参数是字符串,无返回值

函数中的可选参数

在 TypeScript 里每个参数都是可选的,可传可不传;

  1. function people (name: string, age?: number): void {}
  2. people('段然'); // 正确,第二个参数可不传
  3. people('段然', 1); // 正确
  4. people('段然', '1'); // 错误,第二个参数类型传递错误

函数中的剩余参数

在 TypeScript 里可以把剩余的所有参数收集到一个变量里,达到可扩展的目的;

  1. function people (name: string, ...hobby: string[]): void {}
  2. people('段然'); // 正确
  3. people('段然', '1', '2'); // 正确
  4. people('段然', 1, 2); // 错误,剩余的参数类型传递错误

any 与 unknown

image.png

泛型

泛型存在的关键目的是在成员之间提供可扩展性的约束,这些成员可以是:函数参数、函数返回值、接口、类的成员与类的方法等,一句话总结就是:将原本在声明时的约束移动至使用时;

泛型函数

对函数的参数与返回值进行约束;

  1. function eat<T> (food1: T, food2: T): T { return food1 + food2; }
  2. eat<string>('meat', 'agg'); // 使用时传递真实类型
  3. eat<number>(1, 2); // 使用时传递真实类型

泛型接口

对接口进行约束;

  1. interface People<T> {
  2. name: T;
  3. };
  4. function people<T> (name: T): People<T> {
  5. return { name };
  6. }
  7. people<string>('段然'); // 使用时传递真实类型

泛型类

对类中的成员变量与方法进行约束;

  1. class People<T> {
  2. name: T
  3. constructor(name: T) {
  4. this.name = name;
  5. }
  6. say(): T {
  7. return this.name;
  8. }
  9. };
  10. const people = new People<string>('段然'); // 使用时传递真实类型
  11. const people = new People<number>(111); // 使用时传递真实类型

泛型参数的约束

对泛型的参数进行一些约束;

  1. function eat<T extends Length> (food1: T, food2: T): T { return food1 + food2; }
  2. eat<string>('meat', 'egg'); // 正确
  3. eat<number>(1, 2); // 错误,只有含有 length 的参数才可以被传入;

泛型传递多个参数

泛型中可以传递多个参数,通过 “,” 进行分割;

  1. function eat<A, B> (food1: A, food2: B): A { return food1; }
  2. eat<string, number>('meat', 1);

泛型设置默认参数

泛型可以设置默认类型的参数;

  1. function eat<T = string> (food1: T, food2: T): T { return food1 + food2; }
  2. eat('meat', 'egg');