ts 进阶用法 — 1. 接口与类型别名

接口 interface

interface 接口类型

ts中是这样定义 接口的 interface关键字 + 接口名

/ ** 关键字 接口名称 */
interface ProgramLanguage {
  /** 语言名称 */
  name: string;
  /** 使用年限 */
  age: () => number;
}
复制代码

可缺省属性

如下列代码中的id 就是可缺省

interface ProgramLanguage {
  id?: string;
  name: string;
  age: () => number;
}
复制代码

只读属性

通过readonly 修饰符来标注下列代码中的name 为只读

interface ProgramLanguage {
  id?: string;
  readonly name: string;
  age: () => number;
}
复制代码

注意: readonly 只是静态类型检查层面的只读 并不能阻止代码(编译后成es代码)对对象的篡改

接口类型可以用来定义函数类型(可执行类型)

interface StudyLanguage {
  (language: ProgramLanguage): void
}
复制代码

实际使用中我们很少用接口类型来定义函数类型, 使用内联类型或类型别名配合箭头函数预发来定义函数类型方便且快捷

type StudyLanguageType = (language: ProgramLanguage)=> void
复制代码

索引签名

实际工作中, 使用接口类型较多的地方就是对象 如 React Vue组件中的Props & States HTMLElement的Props 这些对象有一个共性 即所有的属性名 方法名都是确定的

我们需要使用索引签名来定义上边提到的对象映射结构,并通过 “[索引名: 类型]”的格式约束索引的类型

interface LanguageRankInterface {
  [rank: number]: string;
}
interface LanguageYearInterface {
  [name: string]: number;
}
复制代码

继承与实现

extends 关键字实现接口继承

ts中我们既可以使用接口类型来约束类 反过来也可以使用类实现接口 那两者之间的关系是什么呢?

/** 类实现接口 */
 class LanguageClass implements ProgramLanguage {
    name: string = '';
    age = () => new Date().getFullYear() - 2012
  }
复制代码

类型别名 type

type 类型别名

type LanguageType = {
   name: string
}
复制代码

类型别名可以 覆盖interface无法覆盖的场景如: 组合类型 交叉类型 亦或是提取接口属性的类型

 /** 联合 */
  type MixedType = string | number;
  /** 交叉 */
  type IntersectionType = { id: number; name: string; } 
    & { age: number; name: string };
  /** 提取接口属性类型 */
  type AgeType = ProgramLanguage['age'];  
复制代码

type的继承

& 操作符实现接口继承

接口与类型别名区别

大多数情况下 interface 与 type 可以相互替代 即效果等价 但少部分场景不同

  1. 重复定义区别
  • 重复定义接口类型在效果上会叠加这使得我们很方便的对全局类型 第三方库类型做扩展
  • 而 type 类型别名重复定义 会出现ts重复标志 错误
  interface Language {
    id: number;
  }
  
  interface Language {
    name: string;
  }
  let lang: Language = {
    id: 1, // ok
    name: 'name' // ok
  }
  
  /** ts(2300) 重复的标志 */
  type Language = {
    id: number;
  }
  
  /** ts(2300) 重复的标志 */
  type Language = {
    name: string;
  }
  let lang: Language = {
    id: 1,
    name: 'name'
  }
复制代码
  1. interface 与 type 可以相互扩展对方 单语法不通 (extends关键字 &操作符)
type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; } // 利用type扩展interface

interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; }; // 利用interface扩展 type
复制代码
  1. 对于class 类的类型: 类可以以相同的方式(implements关键字) 实现interface和type

  2. type可以使用in 关键字生成映射类型 interface不行 (计算所含属性来生成映射类型)

type Keys = "firstname" | "surname"

type DudeType = {
  [key in Keys]: string
}

const test: DudeType = {
  firstname: "Pawel",
  surname: "Grzybek"
}
复制代码

编码建议

公共的用 interface 实现,不能用 interface 实现的再用 type 实现

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享