Skip to content

基本数据类型的兼容性

ts
const str = 'foo'
let strOrNum: string | number

strOrNum = str // OK,满足安全性。

鸭子类型检测

ts
interface Foo {
  toString(): string
}

let foo: Foo = 'foo' // OK,字符串有 toString 方法,满足安全性。

let bar!: Foo
let baz: string = bar // Error,并没有字符串类型除 toString 外的其它方法。

接口的兼容性

ts
interface Foo {
  name: string,
  age: nunmber
}

interface Bar {
  name: string,
  age: number,
  gender: number
}

let foo!: Foo
let bar!: Bar

foo = bar // OK,满足安全性。

函数兼容性

ts
let foo = (x: string, y: string) => {}
let bar = (x: string) => {}

type EachCb<T> = (item: T, index: number) => void
const each = <T>(ary: T[], cb: EachCb<T>) => {
  for (let i = 0, l = ary.length; i < l; i++) {
    cb(ary[i], i)
  }
} 

each([1, 2, 3], (item) => {}) 
// 为了用户体验,参数是可以少传的。因此可以把少的赋值
// 给多的,但不能把多个赋值给少的。

foo = bar // OK,少的赋值给多的(左边参数个数要 >= 右边)

函数的返回值兼容性

遵循基本类型的特性、遵循接口的特性

ts
type foo = () => { name: string }
type bar = () => { name: string, age: number }
let f!: foo
let b!: bar

foo = bar // OK

type foo = () => string | number
type bar = () => string
let f!: foo
let b!: bar
foo = bar

1.基本类型,小范围可以赋给大范围 2.接口类型,大范围可以赋给小范围 3.函数类型(参数、返回值), 参数:少的可以赋给参数多的 返回值遵循1,2,3(第三点的情况是函数返回了一个函数)

协变与逆变

ts
class Foo {
  foo: string = 'foo'
}

class Bar extends Foo {
  bar: number = 10
}

class Baz extends Bar {
  baz: string = 'baz'
}

type Fn = (person: Bar) => Bar // Bar 能处理 foo 和 bar 属性
function fn(cb: Fn) {}

// 参数 逆变 可以传父或自己
fn((person: Bar) => new Bar) // OK
fn((person: Foo) => new Bar) // Ok,少的可以给多的
fn((person: Baz) => new Bar) // Error,不能处理 bar 属性

// 返回值 协变 可以传自己或子
fn((person: Foo) => new Foo) // Error,缺少 bar 属性,少的不能给多的
fn((person: Foo) => new Baz) // Ok,多的可以给少的

// 参数还可以双向协变 参数可以传自己,也可以传父亲(默认在严格模式不支持)

// 函数作为参数时,可以传父返子
function fn(cb: (foo: string | number): number) {}

fn((foo: string | number | boolean) => 1) // OK
fn((foo: string | number | boolean) => '') // Error

类实例的兼容性

遵循接口的兼容性,如果类中出现了 private 或 protected 永远不兼容。

ts
class Foo {
  name: string = 'foo'
}

class Bar {
  name: string = 'bar'
}

class Baz {
  name: string = 'baz'
  age: 18
}

let foo!: Foo
let bar!: Bar
let baz!: Baz

foo = bar
bar = baz
foo = baz
baz = foo // Error

枚举类型永远不兼容

泛型根据最终的结果是否兼容

ts
interface A<T> {

}

interface B<T> {

}

type A1 = A<string>
type B1 = B<number>

let a1!: A1
let b1!: B1

a1 = b1 // Ok,结果都一样,什么都没有,能兼容。


interface A<T> {

}

interface B<T> {
 index: T
}

type A1 = A<string>
type B1 = B<number>

let a1!: A1
let b1!: B1

b1 = a1 // 多的能给少的
a1 = b1 // Error