TypeScript相关知识点整理_概念理解

120 阅读5分钟

通识

  • TS为JS超集,如果采用 JS语法书写的TS文件(无TS语法),浏览器可以直接识别,不需要编译
  • 编写/编译阶段即可检查错误
  • TS静态类型-确定的类型不可变更;JS动态类型-可由赋值更改
  • TS类型 强调大小写,小写为 基础类型,大写为 引用类型(对象)
  • tsc --init会生成初始配置文件 tsconfig.json,此文件所在位置为整个 TS项目的根目录
  • 修改 tsconfig 中的 rootDiroutDir可以配置项目的 源代码目录和输出目录
  • TS中的 any类型声明可以从编写阶段就跳过检查,同时此类型的数据没有提示信息,等效于JS

数据类型:

  • boolean
  • string
  • number
  • null,undefined,any,never,void
  • 数组
  • 元组
  • 枚举
  • object

交叉类型

交叉类型的实现

  • 利用类型别名,接口都可实现
//type定义的交叉类型
type Atype = {
    name: string
}
type Btype = {
    age: number
}
type Ctype = Atype & Btype;

//interface的继承特性
interface Atype {
  name: string;
}
interface Btype {
  age: number;
}
interface Ctype extends Atype, Btype {}
  • 联合类型组成的交叉类型:指代彼此的交集部分;对象结构类型组成的交叉类型,指代彼此的融合
type Atype = number | string;
type Btype = string | boolean;
type Ctype = Atype & Btype; // string

type Atype = {
    name: string
}
type Btype = {
    age: number
}
type Ctype = Atype & Btype; // {name:string, age:number}

类型守卫

类型守卫的作用

  • 设置 校验类型
  • 触发 条件逻辑

使用场景

由于TS是 编译时 语法,联合类型声明的变量 只有在运行时才能确定其 具体类型。因此需要 类型守卫 添加 校验逻辑, 帮助开发运行时不会出错的代码

类型守卫分类

typeof操作符:适用于基础类型

type Atype = number | string;

function add(a:Atype, b:Atype) {
    if(typeof a === 'string' || typeof b === 'string') {   //type guard
        return a.toString() + b.toString()
    }
    return a + b
}

if...in语法结构:适用于对象类型

type Employee = {
    name: string;
    works: string[]
}
type Manager = {
    name: string;
    meetings: string[]
}
type EmployeeOrManager = Employee | Manager;

function printInformation(emp: EmployeeOrManager) {
    if('works' in emp) {  //js 运行时支持的类型守卫
        console.log(emp.works)
    }
}

instanceof操作符:适用于类

class Car {
    drive() {
        console.log('Driving...')
    }
}
class Truck {
    drive() {
        console.log('Driving a truck...')
    }
    loadCargo(amount: number) {
        console.log('Loading cargo ...' + amount)
    }
}
type Vehicle = Car | Truck;
const v1 = new Car();
const v2 = new Truck();
function useVehicle(vehicle: Vehicle) {
    vehicle.drive();
    if(vehicle instanceof Truck) {   //instanceof
        vehicle.loadCargo(1000)
    }
}

===!====!=

  • 适用于字面量类型的区分,null或undefined类型排除

可辨识联合类型

  • 可辨识联合类型:不同类或接口中相同属性名,不同属性值的公共标识
  • 作用:对于复杂的类型,如不同的类或接口之间进行 类型辨别,普通的类型守卫方式难以做到,采用 可辨识联合类型 可以轻松指示区分
interface Bird {
  type: "bird";
  flyingSpeed: number;
}
interface Horse {
  type: "horse";
  runningSpeed: number;
}

type Animal = Bird | Horse;
function moveAnimal(animal: Animal) {
  switch (animal.type) {
    case "bird":
      console.log("Moving with speed: " + animal.flyingSpeed);
      break;
    case "horse":
      console.log("Moving with speed: " + animal.runningSpeed);
  }
}

类型断言

尖括号语法

const inputEle = <HTMLInputElement>document.getElementById('user-output')!;

as语法

const inputEle = document.getElementById('user-output')! as HTMLInputElement;
inputEle.value = 'Hi there';

可索引属性

  • 允许结构扩展,但同时受到类型条件限制
  • 可索引属性部分类型提示
  • 会对固定属性的类型有所限制
interface IndexFace {
    [pros: string]: string;
    name: string; //ok
    id: number;   //error
}

可选链

  • 对象类型,存在某个属性为可选属性时,无法确保一定存在某属性的逻辑简写方式
    console.log(fetchUserData.job?.title)
    

TS中函数指向问题:

  • tsconfig.json配置项中将noImplicitThis设置为true会开启隐式this提示,同时类型检查机制会导致对象方法中的this可能因指向不明确(如隐式any)报错
  • 函数声明方式:this指向调用者,调用以后才确认,开启如上提示会报错
  • 箭头函数能保存函数创建时this指向,而不是调用后,因此需要变化指向需要手动给函数this赋类型
     interface Deck {
         suits: string[],
         cards: number[],
         createCardPicker: (this:Deck) => {}   //this被手动指向了Deck对象类型
     }
    

函数重载

作用场景

  • 函数 返回值联合类型时, 因为 TS类型推断 和 逻辑是不相关的,无法通过逻辑区分返回的具体类型。会导致在实际使用时无法正确使用对应类型的方法
    type Atype = number | string;
    
    function add(a: Atype, b: Atype) {
      if (typeof a === "string" || typeof b === "string") {
        return a.toString() + b.toString();
      }
      return a + b;
    }
    
    //TS会无视逻辑,仍然推断result为 number | string
    const result = add('a','b');
    result.split(''). //error
    
  • 在上述场景下,函数重载 的作用 就是把 各种联合类型传入和传出 情况区分声明,TS能依照对应声明关联输入输出的类型
    • ⚠️函数的逻辑实现要在所有重载声明之后,才能融合所有类型 进行完整的 类型守卫
    function add(a: string, b: Atype): string;
    function add(a: Atype, b: string): string;
    function add(a: number, b: number): number;
    function add(a: Atype, b: Atype) {
      if (typeof a === "string" || typeof b === "string") {
        return a.toString() + b.toString();
      }
      return a + b;
    }
    const result = add("a", 1); //string
    

函数重载相关问题

  • 重载只是让函数传参为多类型时,编写过程更清晰
  • 区别于联合类型的传参方式,重载可以对函数输入输出的类型都有明确限制,如果函数需要针对不同类型参数有不同的处理和返回值,联合类型在写编写过程无法正确提示输出的具体类型
  • 需要注意ts只是开发手段,重载类型被编译为js以后仍然是支持传入任意类型,因此也会存在输入输出为undefined类型的值
  • 匿名函数、箭头函数无法重载