Appearance
基本数据类型的兼容性
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 = bar1.基本类型,小范围可以赋给大范围 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