扩展类型—接口的概念
扩展类型:类型别名、枚举、接口、类、泛型
查阅官方的接口文档、调用一个后台的接口
TypeSript的接口 Interface :用于 约束类、对象、函数等的 契约(标准)
契约(标准)的形式:
- API文档,弱标准:因为开发人员可能写错或者不按这个规范走
- 代码约束,强标准:写错了,编辑器会立即提示你
接口的使用
接口与类型别名还是有区别的,重点是在于 约束类 上。
接口interface和类型别名type都不会出现在编译结果中!!定义接口:
```typescript //关于约束函数 // type Condition = {//这个大括号表示定界符,不再是对象了 // (n:number)=>boolean; // }interface User {
name: string
age: number
//sayHello:() => void//注意:这里千万不要写函数的实现
sayHello():void//也可以写成这种形式
}
//对比类型别名type, 可以认为除了 约束类 以外,它们的差别很细微
type User2={
name: string,
age: number,
sayHello:() => void
}
interface Condition {//Condition就是函数 (n: number): boolean }
function sum(numbers: number[], callback: Condition): number { let s = 0; numbers.forEach(n => { if (callback(n)) { s += n; } }); return s; }
const result = sum([3, 4, 5, 7, 11], n => n % 2 !== 0); console.log(result);
<a name="pTGcA"></a>
## 接口可以(多)继承
```typescript
interface A {
T1: string
}
interface B extends A {//这里还能这样啊, ..强啊
T2: number
}
interface C extends A, B {
//T1: number//这是不允许的, 它不能对A的同名T1成员进行类型更改
T3: boolean
}
let c: C = {
T1: 'A_T1',
T2: 22,
T3: true,
}
console.log(c);
虽然 类型别名 type 也可以实现类似的组合效果—叫做 交叉类型,使用 & ,但是还是有缺陷,故建议使用接口
type A = {
T1: string
};
type B = {
T2: number
};
type C = {
T1: number
T3: boolean
} & A & B;
let c: C = {
T1: 'A_T1',//最终T1是 number&string --> never, 此时赋值什么都会给警告
T2: 22,
T3: true,
}
交叉类型 与 接口继承的区别:
- 接口继承,子接口不能覆盖父接口的成员
- 交叉类型,会把相同成员的类型进行取并集,最终变成never,会报错
readonly修饰符
对象成员名 或 约束类型 前面加上 readonly 即可,所以要区分好readonly修饰的目标是谁!!
一经赋值,不可再次修改
只读修饰符不在编译结果中
变量只读需要用 const ,不要学懵了!
对于readonly数组类型:数组一经赋值,绝对不可更改数组内容了,是浅对比, 但可以直接改变引用(非const下)
如果readonly对象成员名,则成员不可更改引用,但是可以修改具体内容
let arr: readonly number[] = [1,2,3,4];
//arr[0] = 3;//报错
//arr.splice//已经报错了
let arr2: ReadonlyArray<number> = [1,3,5,6];
//
interface User {
readonly name: string
age: number
sayHello(): void
readonly arr: readonly string[] //完全只读,浅对比
}
类型兼容性
如果A<-B,能完成赋值,则B和A类型兼容
带着 欣赏的角度 看看TS是怎么做类型兼容的
类型断言
用法:1. 数据 as 类型 2. <类型>数据 但写法2,在react中并不推荐,容易和组件搞混
也不会出现在编译结果中
鸭子辨型法(子结构辨型法)
目标类型需要某一些特征,赋值的类型只要能满足该特征即可
interface Duck{
sound: '嘎嘎嘎'//这是字面量
swim():void
}
let person = {
name:'伪装成鸭子的人',
age:11,
// sound: '嘎嘎嘎'//这里推断出的是字符串,因为没进行类型约束,但是我们希望把它断言成字面量, 怎么办呢?
sound: '嘎嘎嘎111' as '嘎嘎嘎',
swim(){
console.log(this.name, '正在游泳,并且发出了 ', this.sound, '的声音');
}
}
let duck:Duck = person;//你看, 这样就能完成赋值
例如:假设有个函数用于得到服务器的某个接口的返回结果,是一个用户对象,我不需要所有的字段,我只想用某一小部分字段,怎么办呢
function getUserInfo() {
return {
loginId: '234',
nickName: 'wjw',
gender: "男" as '男',
age: 22,
power: 'strong',
};
}
let u = getUserInfo();
interface ResponseUser {
loginId: string,
nickName: string,
gender: "男" | "女"
}
let user: ResponseUser = u;//这里不能直接用字面量赋值过来,否则就报错
当直接使用对象字面量赋值的时候,将使用更加严格的判断,防止隐患,TS真是细啊!