「TypeScript」类型检查机制


类型检查机制

辅助开发,提高开发效率。

  • 类型推断
  • 类型兼容性
  • 类型保护

类型推断

不需要指定变量类型(韩式的返回值类型),ts 可以根据某些规则自动推断类型。

  • 基础类型推断
let a = 1; // 推断为Number
  • 最佳通用类型推断
let a = [1, null]; // 会尽可能推断为符合当前所有类型的类型
  • 上下文推断
    类型断言
window.onkeydown = (event) => {
  event.button; // 报错,因为button不是键盘事件,而是鼠标事件
};
interface Foo {
  bar: number;
}
let foo = {} as Foo; // 但不能滥用

类型兼容性

兼容:当一个类型可以被赋值给另一个类型。
X 兼容 Y:X(目标类型) = Y(源类型)

let s: string = "";
s = null;
  • 接口兼容性,源类型必须拥有目标类型的必要属性
interface X {
  a: any;
  b: any;
}
interface Y {
  a: any;
  b: any;
  c: any;
}
let x: X = { a: 1, b: 1 };
let y: Y = { a: 1, b: 2, c: 3 };
x = y;
  • 函数兼容性
    需要满足三个条件:
type Handler = (a: number, b: number) => void;
function hor(handler: Handler) {
  return handler;
}
  • 目标函数的参数个数要多于源函数的参数个数,let handler = (a: number) => {},存在可选参数/剩余参数时,固定参数可兼容可选参数和剩余参数,可选参数不兼容固定参数和剩余参数。
  • 参数类型必须匹配
  • 目标函数的返回类型必须要与源函数的返回类型或者子类型
  • 枚举兼容
enum Fruit {
  Apple,
  Banana,
}
enum Color {
  Red,
  Yellow,
}
let fruit: Fruit.Apple = 3;
let no: number = Fruit.Apple; // 枚举和number可以相互兼容
let color: Color.Red = Fruit.Apple; // 报错,不兼容
  • 类兼容性
    静态成员和构造函数不参与比较
    如果类内存在私有成员,即便成员名称相同也不可兼容,除了父类子类之前。
class A {
  constructor(p: number, q: number) {}
  id: number = 1;
}
class B {
  static s = 1;
  constructor(p: number) {}
  id: number = 2;
}
let a = new A(1, 2);
let b = new B(1);
a = b; // 可兼容
b = a; // 可兼容

class C extends A {}
let c = new C(2, 3);
a = c;
  • 泛型兼容
    只有类型参数 T 在被类型成员使用时可能会影响实例的兼容性。
    泛型函数也是类似的,只要参数类型不被使用,那么实例就可以被兼容。
interface Empty<T> {}
let obj_1: Empty<number> = {};
let obj_2: Empty<string> = {};
obj_1 = obj_2; // 兼容

interface Empty<T> {
  value: T;
}
let obj_1: Empty<number> = {};
let obj_2: Empty<string> = {};
obj_1 = obj_2; // 报错

结构之间兼容:成员少的兼容成员多的

函数之间兼容:参数多的兼容参数少的

类型保护

enum Type {
  Strong,
  Weak,
}

class Java {
  helloJava() {
    console.log("hello Java");
  }
}

class JavaScript {
  helloJavaScript() {
    console.log("hello JavaScript");
  }
}

function getLang(type: Type) {
  let lang = type === Type.Strong ? new Java() : new JavaScript();
  // 需要进行类型断言
  if ((lang as Java).helloJava) (lang as Java).helloJava;
  if ((lang as JavaScript).helloJavaScript)
    (lang as JavaScript).helloJavaScript;

  return lang;
}

在多个地方进行类型断言,不利于代码的可读性。

类型保护
TS 能在特定的区块中保证变了属于某种确定的类型。
可以在此区块中放心地引用此类型的属性,或者调用此类型的方法。

  • 使用instanceOf
if (lang instanceof Java) {
  lang.helloJava();
} else {
  lang.helloJavaScript();
}
  • 使用in关键字
if ("helloJava" in lang) {
  lang.helloJava();
} else {
  lang.helloJavaScript();
}
  • 使用type of,判断基本类型
function getLang(x: string | number) {
  if (typeof x === "string") {
    console.log(x.length);
  } else {
    console.log(x + 100);
  }
  return lang;
}
  • 类型保护函数
// 类型保护函数
function isJava(lang: Java | JavaScript): lang is Java {
  return (lang as Java).helloJava !== undefined;
}

文章作者: 阿汪同学
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 阿汪同学 !
评论
  目录