扩展类型—接口的概念

扩展类型:类型别名、枚举、接口、类、泛型

查阅官方的接口文档、调用一个后台的接口

TypeSript的接口 Interface :用于 约束类、对象、函数等的 契约(标准)
契约(标准)的形式:

  • API文档,弱标准:因为开发人员可能写错或者不按这个规范走
  • 代码约束,强标准:写错了,编辑器会立即提示你

    接口的使用

    接口与类型别名还是有区别的,重点是在于 约束类 上。
    接口interface和类型别名type都不会出现在编译结果中!!

    定义接口:

    1. interface User {
    2. name: string
    3. age: number
    4. //sayHello:() => void//注意:这里千万不要写函数的实现
    5. sayHello():void//也可以写成这种形式
    6. }
    7. //对比类型别名type, 可以认为除了 约束类 以外,它们的差别很细微
    8. type User2={
    9. name: string,
    10. age: number,
    11. sayHello:() => void
    12. }
    ```typescript //关于约束函数 // type Condition = {//这个大括号表示定界符,不再是对象了 // (n:number)=>boolean; // }

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);

  1. <a name="pTGcA"></a>
  2. ## 接口可以(多)继承
  3. ```typescript
  4. interface A {
  5. T1: string
  6. }
  7. interface B extends A {//这里还能这样啊, ..强啊
  8. T2: number
  9. }
  10. interface C extends A, B {
  11. //T1: number//这是不允许的, 它不能对A的同名T1成员进行类型更改
  12. T3: boolean
  13. }
  14. let c: C = {
  15. T1: 'A_T1',
  16. T2: 22,
  17. T3: true,
  18. }
  19. console.log(c);

虽然 类型别名 type 也可以实现类似的组合效果—叫做 交叉类型,使用 & ,但是还是有缺陷,故建议使用接口

  1. type A = {
  2. T1: string
  3. };
  4. type B = {
  5. T2: number
  6. };
  7. type C = {
  8. T1: number
  9. T3: boolean
  10. } & A & B;
  11. let c: C = {
  12. T1: 'A_T1',//最终T1是 number&string --> never, 此时赋值什么都会给警告
  13. T2: 22,
  14. T3: true,
  15. }

交叉类型 与 接口继承的区别:

  1. 接口继承,子接口不能覆盖父接口的成员
  2. 交叉类型,会把相同成员的类型进行取并集,最终变成never,会报错

    readonly修饰符

    对象成员名 或 约束类型 前面加上 readonly 即可,所以要区分好readonly修饰的目标是谁!!

一经赋值,不可再次修改
只读修饰符不在编译结果中
变量只读需要用 const ,不要学懵了!

对于readonly数组类型:数组一经赋值,绝对不可更改数组内容了,是浅对比, 但可以直接改变引用(非const下)
如果readonly对象成员名,则成员不可更改引用,但是可以修改具体内容

  1. let arr: readonly number[] = [1,2,3,4];
  2. //arr[0] = 3;//报错
  3. //arr.splice//已经报错了
  4. let arr2: ReadonlyArray<number> = [1,3,5,6];
  5. //
  6. interface User {
  7. readonly name: string
  8. age: number
  9. sayHello(): void
  10. readonly arr: readonly string[] //完全只读,浅对比
  11. }

或者使用 ReadonlyArray

类型兼容性

如果A<-B,能完成赋值,则B和A类型兼容
带着 欣赏的角度 看看TS是怎么做类型兼容的

类型断言

用法:1. 数据 as 类型 2. <类型>数据 但写法2,在react中并不推荐,容易和组件搞混
也不会出现在编译结果中

鸭子辨型法(子结构辨型法)

目标类型需要某一些特征,赋值的类型只要能满足该特征即可

  1. interface Duck{
  2. sound: '嘎嘎嘎'//这是字面量
  3. swim():void
  4. }
  5. let person = {
  6. name:'伪装成鸭子的人',
  7. age:11,
  8. // sound: '嘎嘎嘎'//这里推断出的是字符串,因为没进行类型约束,但是我们希望把它断言成字面量, 怎么办呢?
  9. sound: '嘎嘎嘎111' as '嘎嘎嘎',
  10. swim(){
  11. console.log(this.name, '正在游泳,并且发出了 ', this.sound, '的声音');
  12. }
  13. }
  14. let duck:Duck = person;//你看, 这样就能完成赋值

例如:假设有个函数用于得到服务器的某个接口的返回结果,是一个用户对象,我不需要所有的字段,我只想用某一小部分字段,怎么办呢

  1. function getUserInfo() {
  2. return {
  3. loginId: '234',
  4. nickName: 'wjw',
  5. gender: "男" as '男',
  6. age: 22,
  7. power: 'strong',
  8. };
  9. }
  10. let u = getUserInfo();
  11. interface ResponseUser {
  12. loginId: string,
  13. nickName: string,
  14. gender: "男" | "女"
  15. }
  16. let user: ResponseUser = u;//这里不能直接用字面量赋值过来,否则就报错

直接使用对象字面量赋值的时候,将使用更加严格的判断,防止隐患,TS真是细啊!

  • 基本类型:需要完全匹配
  • 对象类型:鸭子辨型法
  • 函数类型一切无比地自然
    • 比如说,类型定义时没写可选,就是要求有两个参数,但是我函数里没用到第二个参数,所以我不传递第二个参数,最后没问题,不会判断出为错误。即 参数不能多,但是可以少
    • 对于返回值:要求返回必须返回且类型要相同;不要求,则你随意
  • 类 类型:
  • 泛型类型:

    练习:用接口改造扑克牌

    注意使用继承