ts详解

391 阅读4分钟

一、TS基础概念

1、什么是TS
a、原理
  • ts是JavaScript的一个超集,在原有的语法基础上,添加了可选静态类型和基于类的面向对象编程
  • 面向项目:TS - 面向解决大型复杂项目,架构以及代码维复杂的场景 js - 脚本语言,用于面向简单的单一逻辑场景
  • 自主检测:TS - 编译期间,主动发现并纠正问题 js - 运行时报错
  • 类型检测:TS - 支持动态合景泰类型检测 js - 弱类型
  • 运行流程:TS - 依赖编译,依靠编译打包实现浏览器运行 js - 可直接运行
  • 复杂特性:模块化、泛型、接口
b、安装运行
   npm install -g typescript
   tsc -v // 查看版本
   tsc dome.ts // 编译
   // 面试点:所有的类型检查和纠错阶段都在 -- 编译时
2、TS基础类型和写法
  • boolean | string | number | array | null | undefined
   // es 写法
   let isBool = true;
   let str = 'hello world';
   let num = 123;
   let arr = [1, 2, 3];
   let nu = null;
   let und = undefined;
   // ts 写法
   let isBool: boolean = true;
   let str: string = 'hello world';
   let num: number = 123;
   let arr: Array<number> = [1, 2, 3];
   let nu: null = null;
   let und: undefined = undefined;
  • tuple - 元组
   let tuple: [string, number];
   tuple = ['hello', 123];
  • enum - 枚举
   // 数字类型枚举 - 默认从零开始,依次递增
   enum Score {
      BAD, // 0
      NG, // 1
      GOOD, // 2
      PEREACT, // 3
   }
   let sco: Score = Score.GOOD;
   // 字符串枚举
   enum Score {
      BAD = 'bad', // 
      NG = 'ng', // 
      GOOD = 'good', // 
      PEREACT = 'perfect', // 
   }
   let sco: Score = Score.GOOD;
   // 反向映射
   enum Score {
      BAD,
      NG,
      GOOD,
      PEREACT,
   }
   let scoNmae = Score[0]; // scoNmae = 'BAD'
   let scoKey = Score.BAD; // scoKey = 0
   // 异构
   enum Enum {
      A,
      B,
      C = 'C',
      D = 'D',
      E = 6,
      F,
   }
   // 枚举:就是js本质->对象
   let Enum;

   (function (Enum) {
      // 正向
      Enum['A'] = 0;
      Enum['B'] = 1;
      Enum['C'] = 'C';
      Enum['D'] = 'D';
      Enum['E'] = 6;
      Enum['F'] = 7;
      // 反向
      Enum[0] = 'A';
      Enum[1] = 'B';
      Enum['C'] = 'C';
      Enum['D'] = 'D';
      Enum[6] = 'E';
      Enum[7] = 'F';
   })(Enum || (Enum = {}));
  • any | unknown | void
   // any - 绕过所有类型检查 => 所有的检查和编译筛查全部失效
   let a: any = 1;
   a = '1';
   a = true;
   a = [1, 2, 3];
   a = { name: 'zhangsan' };
   a = () => { };
   a = null;
   a = undefined;
   let a1: bloolean = a;
   // unknown - 只能赋值给 any 和 unknown 类型;绕过赋值检查 => 禁止更改传递
   let b: unknown;
   b = 1;
   b = '1';
   b = true;
   let b1: unknown = b; // 正确
   let b2: any = b; // 正确
   let b3: number = b; // 错误
   // void - 表示没有任何类型 | never - 表示永远不会返回
   // void - 声明函数的返回值为空
   function fn(): void {
      console.log('hello world');
   }
   consoloe.log(fn()); // undefined
   // never - 表示永远不会返回 | 永远返回error
   function fn(): never {
      throw new Error('error');
   }
   function fn(): never {
      while (true) { }
   }
  • object / Object - 对象类型
   // object - 非原始类型
   // Ts把JavaScript object分成了两个接口来定义
   interface ObjectConstructor {
      create(o: object | null): any;
   }
   const proto = {};
   Object.create(proto); // {}
   Object.create(null); // {}
   Object.create(undefined); // Error

   // Object - Object.prototype 的属性
   interface Object {
      constructor: Function;
      toStoring(): string;
      toLocaleString(): string;
      valueOf(): Object;
   }

   // 定义Object类的属性
   interface ObjectConstructor{
      new(value: any): any1;
   }
   // {} - 定义空属性
   const obj = {};
   obj.pro = 1;
   obj.toString(); // '[object Object]'

二、接口 - interface

  • 对行为的抽象,具体行为由类实现
   // 描述对象内容
   interface Class {
      name: string;
      time: number;
   }
   let class1: Class = { 
      name: '前端',
      time: 1,
   }
   // 只读 & 任意
   interface Class {
      readonly name: string;
      time: number;
   }
   // 面试 - 和js的应用做比较 const
   let arr: number[] = [1, 2, 3];
   let arr1: ReadonlyArray<number> = arr; // 只读数组
   arr1[0] = 12; // 错误
   arr1.push(4); // 错误
   arr1.length = 100; // 错误
   arr1 = arr; // 错误
   // 
   const arr2 = [1, {name: 1}, 4];
   arr2[0] = 12; // 正确
   arr2.push(5); // 正确
   arr2.length = 100; // 正确
   arr2 = []; // 正确

   // 任意可添加属性
   interface Class {
      readonly name: string;
      time: number;
      [propName: string]: any; // 任意属性
   }

三、交叉类型 - &

   interface A {x: D};
   interface B {x: E};
   interface C {x: F};
   interface D {x: number};
   interface E {x: bloolean};
   interface F {x: string};

   type ABC = A & B & C; // {x: number & bloolean & string}
   let abc: ABC = {
      x: {
         d: 1,
         e: true,
         f: 'hello',
      }
   }

   // 合并冲突
   interface A {
      c: string;
      d: string;
   }
   interface B {
      c: number;
      e: string;
   }
   type AB = A & B; // {c: never, d: string, e: string}
   let ab: AB = {
      d: 'hello',
      e: 'world',
   }
   // 合并的关系是且 => c: never(没有哪一个类型能满足 number & string)

四、断言 - 类型声明、转换 (和编译器的告知交流)

  • 编译时作用
   // as形式声明 阶段声明
   let anyValue: any = 'hello world';
   let anyLength: number = (anyValue as string).length;
   
   // 尖括号形式声明 阶段性声明
   let anyValue: any = 'hello world';
   let anyLength: number = anyValue<string>().length;
   
   // 非空判断
   type ClassTime = () => number;
   const start = (time: ClassTime | undefined) => {
      let num = time!(); // 具体类型待定,但非空确认
   })

五、类型守卫 - 保障在语法的规定范围内,额外确认

  • 多态 - 多种状态(多种类型)
   interface A {
      name: string;
      courses: string[];
   }
   interface B {
      name: string;
      startTime: Date;
   }
   type Class = A | B;
   function getClass(classInfo: Class) {
      if ('courses' in classInfo) {
         console.log(classInfo.courses)
      }
      if('startTime' in classInfo) {
         console.log(classInfo.startTime)
      }
   }
   // typeof - 类型保护
   function getClass(classInfo: Class) {
      if (typeof classInfo.name === 'string') {
         console.log(classInfo.name)
      }
      if (typeof classInfo.startTime === 'object') {
         console.log(classInfo.startTime)
      }
   }
   // instanceof - 类型保护
   const getClass = (classInfo: Class) => {
      if (classInfo instanceof A) {
         console.log(classInfo.startTime)
      }
      if (classInfo instanceof B) {
         console.log(classInfo.courses)
      }
   }

六、查漏补缺

1、函数重载 - 重复定义函数
   // 函数重载
   class Class {
      start(name: string, school: string): string; // 函数重载
      start(name: number, school: number): number;
      start(name: string, school: number): string; // 函数重载
      start(name: number, school: string): string; // 函数重载
      start(name: Combinable, school: Combinaible) {
         if(typeof name === 'string' || typeof name === 'string') {
            //Combinaible - 联合类型
         }
      }
   }
2、泛型 - 重用
  • 让模块可以支持多种类型的数据 - 让类型和值一样,可以被赋值传递
   function getClass<T,U>(classInfo: T, classInfo1: U) {
      return classInfo + classInfo1;
   }
   console.log(getClass<number, string>(1, 'hello world'));
   
   function getClass<T,U>(classInfo: T, classInfo1: U) {
      return `${classInfo}${classInfo1}`
   }

3、装饰器 - decorator
   // tsc --target ES5 --experimentalDecorators
   // experimentalDecorators - 启用装饰器: true
   {
      "compilerOptions": {
         "target": "ES5",
         "experimentalDecorators": true
      }
   }
   // 类装饰器
   function ClassDecorator(target: Function): void {
      target.prototype.getClass = function(): void {
         console.log('class decorator')
      }
   }
   @ClassDecorator // 使用写法
   class Class {
      constructor() {
         console.log('class')
      }
   }
   // 属性装饰器
   // target: Object - 被装饰的类:key -- 被装饰类的属性
   function getWrapper(target: Object, key: string) {
      Object.defineProperty(target, key, {
         console.log('property decorator');
      })
   }
   class Class {
      constructor() {
         console.log('class')
      }
      @getWrapper
      public name: string = 'hello world';
   }