TypeScript文档学习记录

193 阅读10分钟

前言:希望可以通过这篇文章,能够给你得到帮助。(感谢一键三连),前端小白不断升级打怪中...

TypeScript

1. 使用

通过npm(Node.js包管理器)

 npm install -g typescript 

2. 项目配置

tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项

3. 基础类型

  • 布尔值

    let isDone: boolean = false;
    
  • 数字

    和javascript一样,TypeScript里的所有数字都是浮点数。这些浮点数的类型是number.除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript2015引入的二进制和八进制字面量。

    let decLiteral: number = 6;
    let hexLiteral: number = 0xf00d;
    let binaryLiteral: number = 0b1010;
    let octalLiteral: number = 0o744;
    
  • 字符串

    JavaScript程序的另一项基本操作是处理网页或服务器端的文本数据。像其他语言一样,我们使用string表示文本数据类型,可以使用双引号或单引号

    let name: string = 'xxx'
    name = 'xxxx'
    

    模板字符串

    let name: string = `axles`
    let desc: string = `hello,我是${name}`
    
  • 数组

    两中方式:

    let list: number[] = [1, 2, 3];
    let list: Array<number> = [1, 2, 3];
    
  • 元组Tuple

    元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。

    let x: [string, number];
    x = ['sxx', 10] // Ok
    x = [10, 'ds'] // Error
    
    // 已知索引的元素
    console.log(x[0])
    // 越界的元素
    x[3] = 'world'; // OK, 字符串可以赋值给(string | number)类型
    console.log(x[5].toString()); // OK, 'string' 和 'number' 都有 toString
    
    x[6] = true; // Error, 布尔不是(string | number)类型
    
  • 枚举

    enum类型是对JavaScript标准数据类型的一个补充

  • Any

    有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。

    let notSure: any = 4;
    notSure = "maybe a string instead";
    notSure = false; // okay, definitely a boolean
    

    当你只知道一部分数据的类型时,any类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:

    let list: any[] = [1, true, "free"];
    list[1] = 100;
    
    
  • Void

    某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void

    function warnUser(): void {
        console.log("This is my warning message");
    }
    
    

    声明一个void类型的变量没有什么大用,因为你只能为它赋予undefinednull

    let unusable: void = undefined;
    
    
  • Null和undefined

    TypeScript里,undefined和null两者各自有着自己的类型undefined和null

    let u: undefined = undefined;
    let n: null = null;
    
    

    默认情况下null和undefined是所有类型的子类型。就是说可以把null和undefined赋值给number类型的变量

    当你指定了--strictNullChecks标记,nullundefined只能赋值给void和它们各自

    想传入一个 stringnullundefined,你可以使用联合类型string | null | undefined

  • Never

    never类型表示的是那些永不存在的值的类型

    never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型保护所约束时。

    never类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never的子类型或可以赋值给never类型(除了never本身之外)。 即使 any也不可以赋值给never

    // 返回never的函数必须存在无法达到的终点
    function error(message: string): never {
        throw new Error(message);
    }
    
    // 推断的返回值类型为never
    function fail() {
        return error("Something failed");
    }
    
    // 返回never的函数必须存在无法达到的终点
    function infiniteLoop(): never {
        while (true) {
        }
    }
    
    
  • Object

    object表示非原始类型,也就是除numberstringbooleansymbolnullundefined之外的类型。

    declare function create(o: object | null): void;
    
    create({ prop: 0 }); // OK
    create(null); // OK
    
    create(42); // Error
    create("string"); // Error
    create(false); // Error
    create(undefined); // Error
    
    
    类型断言

    类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用

    类型断言有两种形式。 其一是“尖括号”语法:

    let someValue: any = "this is a string";
    
    let strLength: number = (<string>someValue).length;
    
    

    另一个为as语法:

    let someValue: any = "this is a string";
    
    let strLength: number = (someValue as string).length;
    
    

4. 变量声明

letconst是JavaScript里相对较新的变量声明方式

TypeScript是JavaScript的超集,所以它本身就支持letconst

var

let: 当用let声明一个变量,它使用的是词法作用域块作用域

var,let作用域的问题,ES6在这有详解,可以参考:

juejin.cn/post/686813…

5. 接口

TypeScript的核心原则之一是对值所具有的结构进行类型检查

  • 定义

    interface LabelledValue {
      label: string;
    }
    
    
  • 可选属性

    接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。

    带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号。

    interface SquareConfig {
      color?: string;
      width?: number;
    }
    
    function createSquare(config: SquareConfig): {color: string; area: number} {
      let newSquare = {color: "white", area: 100};
      if (config.color) {
        newSquare.color = config.color;
      }
      if (config.width) {
        newSquare.area = config.width * config.width;
      }
      return newSquare;
    }
    
    let mySquare = createSquare({color: "black"});
    
    
  • 只读属性

    一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly来指定只读属性:

    interface Point {
        readonly x: number;
        readonly y: number;
    }
    
    let p1: Point = { x: 10, y: 20 };
    p1.x = 5; // error!
    
    

    TypeScript具有ReadonlyArray类型,它与Array相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改:

    let a: number[] = [1, 2, 3, 4];
    let ro: ReadonlyArray<number> = a;
    ro[0] = 12; // error!
    ro.push(5); // error!
    ro.length = 100; // error!
    a = ro; // error!
    
    

    上面代码的最后一行,可以看到就算把整个ReadonlyArray赋值到一个普通数组也是不可以的。 但是你可以用类型断言重写:

    a = ro as number[];
    
    
  • readonly vs const

  • 最简单判断该用readonly还是const的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly

  • 额外的属性检查

    对象字面量会被特殊对待而且会经过 额外属性检查 , 使用类型断言会 绕开这些检查

    interface SquareConfig {
        color?: string;
        width?: number;
    }
    
    function createSquare(config: SquareConfig): { color: string; area: number } {
        // ...
    }
    // error: 'colour' not expected in type 'SquareConfig'
    let mySquare = createSquare({ colour: "red", width: 100 });
    
    
  • 类型断言

    let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
    
    
  • 跳过检查的三种方式

    • 类型断言

      let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
      
      
    • 字符串索引签名

      interface SquareConfig {
          color?: string;
          width?: number;
          [propName: string]: any;
      }
      
      
    • 对象赋值给一个另一个变量

      let squareOptions = { colour: "red", width: 100 };
      let mySquare = createSquare(squareOptions);
      
      
  • 函数类型

    接口能够描述JavaScript中对象拥有的各种各样的外形,除了描述带有属性的普通对象外,接口也可以描述函数类型。

    interface SearchFunc {
      (source: string, subString: string): boolean;
    }
    
    
    let mySearch: SearchFunc;
    mySearch = function(source: string, subString: string) {
      let result = source.search(subString);
      return result > -1;
    }
    
    

    函数的参数名不需要与接口定义的名字相匹配;

    参数类型不指定类型,TypeScript类型系统会推断出参数类型

  • 实现接口

    接口描述了类的公共部分,而不是公共和私有两部分。 它不会帮你检查类是否具有某些私有成员

    interface ClockInterface {
        currentTime: Date;
        setTime(d: Date);
    }
    
    class Clock implements ClockInterface {
        currentTime: Date;
        setTime(d: Date) {
            this.currentTime = d;
        }
        constructor(h: number, m: number) { }
    }
    
    
  • 类静态部分与实例部分的区别

    类是具有两个类型的:静态部分的类型和实例的类型

  • 继承接口

    和类一样,接口也可以相互继承 , 一个接口可以继承多个接口

  • 混合类型

  • 接口继承类

6. 类

传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但对于熟悉使用面向对象方式的程序员来讲就有些棘手,因为他们用的是基于类的继承并且对象是由类构建出来的。 从ECMAScript 2015,也就是ECMAScript 6开始,JavaScript程序员将能够使用基于类的面向对象的方式。

  • 定义

    class Greeter {}
    
    
  • 继承

    类从基类中继承了属性和方法 , 通过 extends关键字。 派生类通常被称作 子类,基类通常被称作 超类

    派生类包含了一个构造函数,它 必须调用 super(),它会执行基类的构造函数。 而且,在构造函数里访问 this的属性之前,我们 一定要调用 super()

  • 公共,私有与受保护的修饰符

    • public

      在TypeScript里,成员都默认为 public

    • private

      当成员被标记成 private时,它就不能在声明它的类的外部访问

      class Animal {
          private name: string;
          constructor(theName: string) { this.name = theName; }
      }
      
      new Animal("Cat").name; // 错误: 'name' 是私有的.
      
      
    • protected

      protected修饰符与 private修饰符的行为很相似,但有一点不同, protected成员在派生类中仍然可以访问。

      构造函数也可以被标记成 protected。 这意味着这个类不能在包含它的类外被实例化,但是能被继承。

    • readonly

      readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化

  • 静态属性

    使用 static定义 属性,通过类名来访问属性

  • 抽象类

    抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。

    abstract class Department {
    
        constructor(public name: string) {
        }
    
        printName(): void {
            console.log('Department name: ' + this.name);
        }
    
        abstract printMeeting(): void; // 必须在派生类中实现
    }
    
    class AccountingDepartment extends Department {
    
        constructor() {
            super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()
        }
    
        printMeeting(): void {
            console.log('The Accounting Department meets each Monday at 10am.');
        }
    
        generateReports(): void {
            console.log('Generating accounting reports...');
        }
    }
    
    let department: Department; // 允许创建一个对抽象类型的引用
    department = new Department(); // 错误: 不能创建一个抽象类的实例
    department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值
    department.printName();
    department.printMeeting();
    department.generateReports(); // 错误: 方法在声明的抽象类中不存在
    
    

7. 函数

和JavaScript一样,TypeScript函数可以创建有名字的函数和匿名函数。

8. 枚举

使用枚举可以定义一些带名字的常量,使用枚举可以清晰地表达意图或创建一组有区别的用例;

  • 数字枚举

    enum Direction {
        Up,
        Down,
        Left,
        Right,
    }
    
    

    Up的值为 0Down的值为 1 , 自增长的行为

    enum Direction {
        Up = 1,
        Down,
        Left,
        Right
    }
    
    

    Down为2,left为3

  • 字符串枚举

    在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。 字符串枚举没有自增长的行为.

    enum Direction {
        Up = "UP",
        Down = "DOWN",
        Left = "LEFT",
        Right = "RIGHT",
    }
    
    
  • 异构枚举

    枚举可以混合字符串和数字成员

  • 计算的和常量成员

9. 泛型

使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

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

泛型接口

interface GenericIdentityFn<T> {
    (arg: T): T;
}

泛型类

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

泛型约束

泛型约束,不再适用于任意类型

10. 类型推论

11. 类型兼容性

12. 高级类型

13. Symbols

14. 迭代器和生成器

15. 模块

16. 命名空间

17. 命名空间和模块

18. 模块解析

19. JSX

20. 装饰器

21. Mixins

22. 三斜线指令

23. JavaScript文件类型检查