TS类型检查机制

1,598 阅读3分钟

TS类型检查机制:

TypeScript编译器在做类型检查时,所秉承的一些原则,以及表现出的一些行为。

作用:

辅助开发,提高开发效率

类型推断

类型推断:

不需要指定变量的类型(函数的返回值类型),TypeScript可以根据某些规则自动地为其推断出一个类型。

基础类型推断

let a // a: any
let b = [1, null] // 当"strictNullChecks": false时, b: number,为true时为: b: (number | null)[]
let c = (x = 1) => x + 1 // c: number

最佳通用类型推断 上下文类型推断

类型断言

interface Foo {
  bar: number
}
let foo = {} as Foo

当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型中共有的属性或方法:

interface Cat {
  name: string;
  run(): void;
}
interface Fish {
  name: string;
  swim(): void;
}
function getName(animal: Cat | Fish) {
  return animal.name;
}

而有时候,我们确实需要在还不确定类型的时候就访问其中一个类型特有的属性或方法,比如:

interface Cat {
  name: string;
  run(): void;
}
interface Fish {
  name: string;
  swim(): void;
}
function isFish(animal: Cat | Fish) {
  if (typeof animal.swim === 'function') {
    return true;
  }
  return false;
}

上面的例子中,获取 animal.swim 的时候会报错。

此时可以使用类型断言,将 animal 断言成 Fish:

interface Cat {
  name: string;
  run(): void;
}
interface Fish {
  name: string;
  swim(): void;
}

function isFish(animal: Cat | Fish) {
  if (typeof (animal as Fish).swim === 'function') {
    return true;
  }
  return false;
}

需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误

TS类型兼容

类型兼容性用于确定一个类型是否能赋值给其他类型,TypeScript 结构化类型系统的基本规则是,如果 x 要兼容 y,那么 y 至少具有与 x 相同的属性。

let x: X = {a: 1, b: 2}
let y: Y = {a: 1, b: 2, c: 3}
x = y // OK
// y = x // Error
  • 如果类型A可以被赋值给类型B,那么就可以说类型B兼容类型A
  • 如果 : B(目标类型) = A(源类型) , 则 : 类型B兼容类型A

这就是为什么说,当一只鸟走起来像鸭子,游起来像鸭子,而且叫起来像鸭子,那么这只鸟就可以被认为是鸭子

函数兼容

一般地,当两个函数相互赋值时,就发生函数兼容, 例如方法的参数为一个函数类型,当调用该方法传参时,就会发生函数兼容 此时,函数类型的这个参数就是目标类型,将要传入的参数为源类型

1.参数个数

let handler1 = (a: number) => {}
hof(handler1)
let handler2 = (a: number, b: number, c: number) => {}
// hof(handler2) // Error
  1. 可选参数和剩余参数
let a = (p1: number, p2: number) => {}
let b = (p1?: number, p2?: number) => {}
let c = (...args: number[]) => {}
a = b // 固定参数兼容可选参数
a = c
b = c // 可选参数不可兼容剩余参数和固定参数 strictFunctionTypes: false时可兼容 
b = a
c = a // 剩余参数可以固定参数和可选参数
c = b

函数兼容

let p3d = (point: Point3D) => {}
let p2d = (point: Point2D) => {}
p3d = p2d // 成员个数多的兼容成员个数少的
p2d = p3d // strictFunctionTypes: false时可兼容