类型检查机制:TypeScript编译器在做类型检查时,所秉承的一些原则,以及表现出的一些行为。
作用:辅助开发,提高开发效率。
类型检查机制通常有:

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

类型推断

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

  • 基础类型推断
  • 最佳通用类型推断
  • 上下文类型推断
  1. /**
  2. * 基础类型推断
  3. */
  4. let a = 1
  5. let b = [1]
  6. // let c = (x = 1) => {}
  7. let d = (x = 1) => x + 1
  8. /**
  9. * 最佳通用类型推断:从多个类型推断类型,TS会推荐兼容所有类型的类型
  10. */
  11. // slet e = [1, null]
  12. /**
  13. * 上下文类型推断:从左往右进行推断,上面是从右往左进行推断
  14. */
  15. window.onkeydown = (event) => {
  16. // console.log(event.button)
  17. }
  18. /**
  19. * 类型断言 as
  20. * 使用类型断言可以增加代码的灵活性,但是不可滥用,要对上下文有充足的预判,否则会有安全隐患
  21. */
  22. interface Foo {
  23. bar: number
  24. }
  25. // let foo = {} as Foo
  26. // foo.bar = 1
  27. let foo: Foo = {
  28. bar: 1
  29. }

类型兼容性

当一个类型Y可以被赋值给另一个类型X时,我们就可以说类型X兼容类型Y
X兼容Y:X(目标类型) = Y(源类型)
口诀:
结构之间兼容: 成员少的兼容成员多的
函数之间兼容: 参数多的兼容参数少的

  1. /**
  2. * 基础类型推断
  3. */
  4. let a = 1
  5. let b = [1]
  6. // let c = (x = 1) => {}
  7. let d = (x = 1) => x + 1
  8. /**
  9. * 最佳通用类型推断:从多个类型推断类型,TS会推荐兼容所有类型的类型
  10. */
  11. // slet e = [1, null]
  12. /**
  13. * 上下文类型推断:从左往右进行推断,上面是从右往左进行推断
  14. */
  15. // window.onkeydown = (event) => {
  16. // // console.log(event.button)
  17. // }
  18. /**
  19. * 类型断言 as
  20. * 使用类型断言可以增加代码的灵活性,但是不可滥用,要对上下文有充足的预判,否则会有安全隐患
  21. */
  22. interface Foo {
  23. bar: number
  24. }
  25. // let foo = {} as Foo
  26. // foo.bar = 1
  27. let foo: Foo = {
  28. bar: 1
  29. }
  30. /**
  31. * 类型兼容
  32. * X兼容Y:X(目标类型) = Y(源类型)
  33. */
  34. // 关闭strictNullChecks时,字符串类型可以赋值null,这时,我们就可以说字符型兼容null类型
  35. let s: string = 'a'
  36. s = null
  37. // 接口兼容性
  38. // 成员少的兼容成员多的
  39. interface X {
  40. a: any;
  41. b: any;
  42. }
  43. interface Y {
  44. a: any;
  45. b: any;
  46. c: any;
  47. }
  48. let z: X = {a: 1, b: 2}
  49. let y: Y = {a: 1, b: 2, c: 3}
  50. x = y
  51. // y = x
  52. // 函数兼容性
  53. type Handler = (a: number, b: number) => void
  54. function hof(handler: Handler) {
  55. return handler
  56. }
  57. // 1).参数个数:目标函数的参数个数要多于源函数的参数个数
  58. let handler1 = (a: number) => {}
  59. hof(handler1)
  60. let handler3 = (a: number, b: number, c: number) => {}
  61. // hof(handler3)
  62. // 可选参数和剩余参数
  63. // 关闭strictFunctionTypes,可以兼容
  64. let a1 = (p1: number, p2: number) => {}
  65. let b1 = (p1?: number, p2?: number) => {}
  66. let c1 = (...args: number[]) => {}
  67. a1 = b1
  68. a1 = c1
  69. b1 = c1
  70. b1 = a1
  71. c1 = a1
  72. c1 = b1
  73. // 2).参数类型
  74. let handler4 = (a: string) => {}
  75. // hof(handler4)
  76. interface Point3D {
  77. x: number;
  78. y: number;
  79. z: number;
  80. }
  81. interface Point2D {
  82. x: number;
  83. y: number;
  84. }
  85. let p3d = (point: Point3D) => {};
  86. let p2d = (point: Point2D) => {};
  87. p3d = p2d
  88. // 关闭strictFunctionTypes可兼容以下
  89. p2d = p3d
  90. // 这种函数参数之间相互赋值的情况,叫做函数参数的双向协变
  91. // 3).返回值类型
  92. let h = () => ({name: 'Alice'});
  93. let g = () => ({name: 'Alice', location: 'shanghai'});
  94. h = g
  95. // g = h
  96. function overload1(a: number, b: number): number;
  97. function overload1(a: string, b: string): string;
  98. function overload1(a: any, b: any): any {};
  99. // 枚举兼容性
  100. enum Fruit { Apple, Banana }
  101. enum Color { Red, Green }
  102. let fruit: Fruit.Apple = 3
  103. let no: number = Fruit.Apple
  104. // 枚举之间是完全不兼容的
  105. // let color: Color.Red = Fruit.Apple
  106. // 类兼容性
  107. // 如果类中含有私有成员,则这两种类就不兼容,只有父类和子类相互兼容
  108. class J {
  109. constructor(p: number, q: number) {}
  110. id: number = 1
  111. // private name: string = ''
  112. }
  113. class K {
  114. static s = 1
  115. constructor(p: number) {}
  116. id: number = 2
  117. }
  118. let aa = new J(1,2);
  119. let bb = new K(1);
  120. aa = bb
  121. bb = aa
  122. class L extends J {}
  123. let cc = new L(1, 2)
  124. aa = cc
  125. cc = aa
  126. // 泛型兼容性
  127. // 泛型接口中没有任何成员是可以相互兼容的
  128. interface Empty<T> {
  129. value: T
  130. }
  131. // let obj1: Empty<number> = {};
  132. // let obj2: Empty<string> = {};
  133. // obj1 = obj2
  134. // 泛型函数的定义相同,但是没有指定类型参数,他们之间也是项目兼容的
  135. let log3 = <T>(x: T): T => {
  136. console.log('x')
  137. return x
  138. }
  139. let log4 = <U>(y: U): U => {
  140. console.log('y')
  141. return y
  142. }
  143. log3 = log4

类型保护

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

  1. enum Type { Strong, Week }
  2. class Java {
  3. helloJava() {
  4. console.log('hello Java')
  5. }
  6. java: any
  7. }
  8. class JavaScript {
  9. helloJavaScript() {
  10. console.log('hello JavaScript')
  11. }
  12. javascript: any
  13. }
  14. function isJava(lang: Java | JavaScript): lang is Java {
  15. return (lang as Java).helloJava !== undefined
  16. }
  17. function getLanguage(type: Type, x: string | number) {
  18. let lang = type === Type.Strong ? new Java() : new JavaScript()
  19. // if ((lang as Java).helloJava) {
  20. // (lang as Java).helloJava()
  21. // } else {
  22. // (lang as JavaScript).helloJavaScript()
  23. // }
  24. // instanceof
  25. // if ( lang instanceof Java ) {
  26. // lang.helloJava()
  27. // } else {
  28. // lang.helloJavaScript()
  29. // }
  30. // in
  31. // if ('java' in lang) {
  32. // lang.helloJava()
  33. // } else {
  34. // lang.helloJavaScript()
  35. // }
  36. // typeof
  37. // if (typeof x === 'string') {
  38. // x.length
  39. // } else {
  40. // x.toFixed(2)
  41. // }
  42. //
  43. if(isJava(lang)) {
  44. lang.helloJava()
  45. } else {
  46. lang.helloJavaScript()
  47. }
  48. return lang
  49. }
  50. getLanguage(Type.Strong)