ts类型兼容
- 结构类型:结构类型是一种只用其成员来描述类型的方式,比如类,接口。兼容性规则:(1)如果 x 要兼容 y(即 x = y),那么y至少要具有x相同的属性;(2)或者说只能将 “子类” 赋值 给 “父类”,反过来不成立;检查函数参数的时候也是这种兼容性规则
例1,可以使用第(1)中理解,y 中包含了 name 属性
interface Named {
name: string;
}
let x: Named
let y = { name: 'Alice', location: 'Seattle' }
x = y
例2,可以使用第(1)中理解,y 中包含了 name 属性
function greet(n: Named) {
console.log('Hello, ' + n.name)
}
greet(y)
例3 使用第一种理解:p2包含了name属性,p1也包含了name属性
使用第二种理解:Mytype 和 Person 都只有一个name属性,所以可以看成 Person 继承了 MyType,又可以看成 Mytype 继承了 Person,所以 MyType 和 Person 都可以被看做成 "子类" 和 "父类",p1 = p2 时,Person 作为 "子类",p2 = p1 时,MyType 作为 "子类"
interface MyType {
name: string
}
class Person {
name: string = '123'
}
let p1: MyType
let p2: Person
p1 = p2 // ok
p2 = p1 // ok
- 函数:兼容性规则:
(1) 参数:
y = x 则 x 里面的每一个参数及其类型 都能在 y 里面找到对应的参数及其类型(参数名可以不同,看类型就行了,)
并且顺序不能颠倒,在下面的例子中如果 换成 b:string, s:number 则报错,无法赋值
(2) 返回值:
源函数(赋值语句右边)的返回值类型必须是目标函数(赋值语句左边)返回值类型的子类型,{ name: ‘Alice’ } 可以看做成 { name: ‘Alice’, location: ‘Seattle’ } 的 “父类”
// 比较两个函数是否兼容
let x = (a: number) => 0
let y = (b: number, s: string) => 0
y = x // OK
// x = y // Error y 函数的参数 s,x 函数不具备
let x1 = () => ({ name: 'Alice' })
let y1 = () => ({ name: 'Alice', location: 'Seattle' })
x1 = y1 // OK
// y1 = x1; // Error, because x() lacks a location property
- 枚举:枚举类型与枚举类型(不兼容),枚举类型与数字类型(兼容)
enum Color {
red,
green
}
enum Status {
finished,
error,
success
}
let num: number
num = Color.red
console.log(num)
num = Status.finished
console.log(num)
let myname = Color.red
// myname = Status.success // 不能将类型“Status.success”分配给类型“Color”。
- 类:比较两个类类型的对象时,只有实例的成员会被比较(比较的是类型和数量)。 静态成员和构造函数不在比较的范围内。类的私有成员和受保护成员会影响兼容性.
兼容性规则:- 源类型(赋值语句右边)必须包含目标类型(赋值语句左边)的成员
- 如果目标类型包含一个私有成员,那么源类型必须包含来自 同一个 类 的这个私有成员.(注意是来自同一个类,而不是两个类分别在类中分别定义了私有属性) 同样地,这条规则也适用于包含受保护成员实例的类型检查
- 允许子类赋值给父类
class Animal {
feet: number
// private mySelf: string
constructor(name: string, numFeet: number) {}
}
class Size {
// private mySelf: string
feet: number
num: number
constructor(numFeet: number) {}
}
class Son extends Size {}
let a: Animal
let s: Size
let d: Son
a = s // OK
// s = a // error 不包含 num 成员
s = d // ok
如果将 Animal 类和Size类中的 定义私有成员的注释去掉,则 a = s
会报错,因为含有了不来自同一个类的私有成员,而 s = d 是正常的,因为 允许子类赋值给父类
- 泛型:看成员和类型,兼容性规则:没有成员的时候,与类型无关;含有成员的时候类型必须一致;没有指定类型的时候被当做 any 看待;
interface Empty<T> {
}
let x: Empty<number>
let y: Empty<string>
x = y // ok,虽然类型不同,但是Empty没有成员,所以在使用时并没有什么不同
interface NotEmpty<T> {
data: T
}
let x: NotEmpty<number>
let y: NotEmpty<string>
x = y //error 含有成员 data 类型不同会有影响
let identity = function<T>(x: T): T {
// ...
}
let reverse = function<U>(y: U): U {
// ...
}
identity = reverse // OK, because (x: any) => any matches (y: any) => any