1. 接口
类型兼容性
type
和 interface
声明的效果都是这样
ChildType
包含ParentType
的全部属性,这样的结构为 父子类型结构
p1=c1
的赋值操称为 协变,展现形式就是增量的参数结构关系赋值
type ParentType = {
name: string
age: number
}
type ChildType = {
name: string
age: number
sex: string
}
let p1: ParentType = {
name: 'p1',
age: 20
}
let c1: ChildType = {
name: 'p1',
age: 20,
sex: 'man'
}
c1 = p1 // 报错:类型 "ParentType" 中缺少属性 "sex",但类型 "ChildType" 中需要该属性
p1 = c1 // 正确:在TS中允许这样的赋值
2. 函数 -- 参数
类型兼容性
- 注意的是:参数的名字相同与否无所谓,只看它们的类型
y=x
, 参数多的=
参数少的:可以,因为是忽略类型定义,不容易导致错误
x=y
, 参数少的=
参数多的:可以,因为是增加参数定义,可能导致错误
let x = (a: number) => 0
let y = (b: number, s: string) => 0
y = x
x = y
3. 函数 -- 返回值
类型兼容性
m = n
, 参数少的=
参数多的:可以,因为是增加参数返回,必要的字段还在
n = m
, 参数多的=
参数少的:不行,因为是减少参数返回,可能导致取不到值
- 类型系统强制源函数的返回值类型必须是目标函数返回值类型的子类型 , 也就是等号后的返回值队列需大于且包含接受赋值的函数返回值队列
let m = () => ({name: 'Alice'})
let n = () => ({name: 'Alice', location: 'Seattle'})
m = n
n = m
4. 函数 -- 可选参数及剩余参数
类型兼容性
- 这个例子说明:剩余参数存在不确定性和不安全的特点
- 如果可以的话,尽量还是使用接口的形式去约束函数参数
function invokeLater(args: any[], callback: (...args: any[]) => void) {
}
invokeLater([1, 2], (x, y) => console.log(x + ', ' + y));
invokeLater([1, 2], (x?, y?) => console.log(x + ', ' + y));
5. 枚举
类型兼容性
- 枚举类型与数字类型兼容
- 并且数字类型与枚举类型兼容
- 不同枚举类型之间是不兼容的
enum Status { Ready, Waiting }
enum Color { Red, Blue, Green }
let s = Status.Ready
let num: number = 1
num = Status.Ready
s = 0
s = 1
s = Color.Red
6. 类
类型兼容性
- 其兼容性与对象字面量和接口差不多
不同
:类有静态部分和实例部分的类型,比较两个类类型的对象时,只有实例的成员会被比较,静态成员和构造函数不在比较的范围内
class Animal {
feet: number = 4
constructor(name: string, numFeet: number) { }
}
class Size {
feet: number = 4
constructor(numFeet: number) { }
}
let a1: Animal = new Animal('a1', 4)
let s1: Size = new Size(4)
a1 = s1
s1 = a1
7. 类 -- 私有成员和受保护成员
类型兼容性
- 类的私有成员和受保护成员会影响兼容性
- 这允许子类赋值给父类
class Animal2 {
protected tag: string = 'Animal2'
feet: number = 4
constructor(name: string, numFeet: number) { }
}
class Size2 {
private tag: string = 'Size2'
feet: number = 4
constructor(numFeet: number) { }
}
class Person2 {
feet: number = 2
constructor(numFeet: number) { }
}
let a2: Animal2 = new Animal2('a1', 4)
let s2: Size2 = new Size2(4)
let p2: Person2 = new Person2(4)
a2 = s2 // Error
s2 = a2 // Error
a2 = p2 // Error: 类型 "Person2" 中缺少属性 "tag",但类型 "Animal2" 中需要该属性
s2 = p2 // Error: 类型 "Person2" 中缺少属性 "tag",但类型 "Size2" 中需要该属性
p2 = a2 // OK
p2 = s2 // OK
8. 泛型
类型兼容性
- 因为TypeScript是结构性的类型系统,类型参数只影响使用其做为类型一部分的结果类型
interface Empty<T> {}
let e1: Empty<number> = { x: 1 };
let e2: Empty<string> = { x: '1' };
e1 = e2;
interface NotEmpty<T> {
data: T;
}
let e3: NotEmpty<number> = { data: 1 };
let e4: NotEmpty<string> = { data: '1' };;
e3 = e4;
let identity = function<T>(x: T): T {}
let reverse = function<U>(y: U): U {}
identity = reverse;