Typescript的结构性子类型是根据Javascript代码的典型写法来设计的。 因为Javascript里广泛的使用匿名对象,例如函数表达式和对象字面量,所以使用结构类型系统来描述这些类型比使用名义类型系统更好。

Typescript结构化类型的基本原则是:如果**x**要兼容**y,**那么**y**至少要具有与**x**相同的属性。

注意:字面量对象兼容的前提是,兼容的值的双方都已经赋值了。并且初始化值的时候,肯定满足对应的类型。

  1. let a: { a: number }
  2. a = { a: 1, b: 2 } // Error
  3. // 不能将类型“{ a: number; b: number; }”分配给类型“{ a: number; }”。
  4. // 对象文字可以只指定已知属性,并且“b”不在类型“{ a: number; }”中。

值初始化之后,再次赋值的时候,开始检查并满足结构化赋值。

  1. let a = {
  2. a: 1
  3. }
  4. let b = {
  5. a: 1,
  6. b: 2
  7. }
  8. a = b // Success
  9. b = a // Error
  10. // 类型 "{ a: number; }" 中缺少属性 "b",但类型 "{ a: number; b: number; }" 中需要该属性。

基础类型的结构化兼容

基础类型的兼容,只需要保证赋值的类型满足对应的就可以。

  1. const a = '123'// a:'123'

对象的结构化兼容

对象的字面量初始化

例子如上:👆🏻

通过类或者构造函数进行对象的初始化

  1. class A {
  2. x = 0
  3. y = 'name'
  4. }
  5. let a: { x: number } = new A() // Success

函数参数

  1. function A(a: number, b: { a: number }) {
  2. console.log(a, b)
  3. }
  4. A(1, { a: 1, b: 2 }) // Error: 第二个参数没有b这个属性。
  1. function A(a: number, b: { a: number }) {
  2. console.log(a, b)
  3. }
  4. const d = { a: 1, b: 2 }
  5. A(1, d) // Success

函数变量

  1. let x = (a: number) => {
  2. console.log(a)
  3. }
  4. let y = (b: number, s: string) => {
  5. console.log(b, s)
  6. }
  7. x = y // Error
  8. y = x // Success let y: (b: number, s: string) => void
  1. y赋值给x,也就是形参多的不可以赋值给形参少的。防止赋值或参数传递变少,变少会影响结果。
  2. x赋值给y,也就是形参少的,可以赋值给形参多的。参数可以和原来一样或者变少了,变少了不会影响结果,变多只是可能会影响结果。

不建议这样进行结构化兼容。要么就写函数重载。