- ts 接口
interface - 在 ts 中,我们使用接口(Interfaces)来定义对象的类型。
- 在面向对象语言中,接口(Interfaces)是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。
- ts 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。赋值的时候,变量的形状必须和接口的形状保持一致。
- 接口命名规范:一般首字母大写,建议接口的名称加上
I前缀,表示它是 ts 中的接口类型。 - 定义接口时,每个字段结束可以加一个分号也可以不加分号
interface IPerson {name: string;age: number;}// ok “形状”一致let p1: IPerson = {name: "p1",age: 1,};// error “形状”不一致let p2: IPerson = {name: "p2",};// error “形状”不一致let p3: IPerson = {name: "p3",age: 3,gender: "male",};
- 在接口中描述一个可选字段
<字段> ?: <类型>
interface IPerson {name: string;age?: number; // age 可有可无}// oklet p1: IPerson = {name: "p1",};// oklet p2: IPerson = {name: "p2",age: 2};// error “形状”不一致let p3: IPerson = {name: "p3",age: 3,gender: "male",};
当你去访问一个可选属性时,ts 会提示它是一个联合类型,比如 typeof p1.age 得到的结果是 number | undefined
- 在接口中描述任意属性
[propName: string]: any - 一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
- 一个接口中只能定义一个任意属性
- 如果接口中有多个类型的属性,则可以在任意属性中使用联合类型
interface IPerson {name: stringage?: number // age 可有可无[propName: string]: any}// oklet p1: IPerson = {name: "p1",age: 1,// 以下皆为任意属性 [propName: string]: anygender: "male",a: 'a',bc: 'bc'};
interface IPerson {name: string;// error 类型“number | undefined”的属性“age”不能赋给“string”索引类型“string”。age?: number;[propName: string]: string;}
interface IPerson {name: string;// okage?: number; // age 可能是 number、undefined[propName: string]: string | number | undefined;}
- 只读属性
readonly - 有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用
readonly定义只读属性 - 只读属性必须在定义的同时完成初始化,且后续不可更改
interface IPerson {readonly id: number;name: string;age?: number;[propName: string]: any;}let tom: IPerson = {id: 89757,name: "Tom",gender: "male",};// error 无法为“id”赋值,因为它是只读属性。tom.id = 9527;
interface IPerson {readonly id: number;name: string;age?: number;[propName: string]: any;}// error 类型 "{ name: string; gender: string; }" 中缺少属性 "id",但类型 "IPerson" 中需要该属性。let tom: IPerson = {name: 'Tom',gender: 'male'};
- 【应用场景】接口 vs. 类型别名
interface用来描述对象、类的结构type用来描述非对象、类的结构- 以上仅是建议,在很多场景下
interface、type可相互替代,可自行选择喜欢的写法,并在工程中一以贯之便是。
- 接口是一系列抽象方法的声明,是一些方法特征的集合,这些方法都应该是抽象的,需要由具体的类去实现,然后第三方就可以通过这组抽象方法调用,让具体的类执行具体的方法
- ts 中定义接口的语法
interface <接口名> { ... }
interface IPerson {firstName: string,lastName: string,sayHi: () => string}var customer: IPerson = {firstName: "Tom",lastName: "Hanks",sayHi: (): string => { return "Hi there" }}console.log("Customer 对象 ")console.log(customer.firstName)console.log(customer.lastName)console.log(customer.sayHi())var employee: IPerson = {firstName: "Jim",lastName: "Blakes",sayHi: (): string => { return "Hello!!!" }}console.log("Employee 对象 ")console.log(employee.firstName)console.log(employee.lastName)console.log(employee.sayHi())// Customer 对象// Tom// Hanks// Hi there// Employee 对象// Jim// Blakes// Hello!!!
// 接口interface RunOptions {program: string;// 联合类型commandline: string[] | string | (() => string);}// commandline 是字符串var options: RunOptions = { program: "test1", commandline: "hello" };console.log(options.commandline);// commandline 是字符串数组options = { program: "test1", commandline: ["Hello", "World"] };// 类型守卫if (Array.isArray(options.commandline)) {console.log(options.commandline[0]);console.log(options.commandline[1]);}// commandline 是一个函数表达式options = { program: "test1", commandline: () => "**Hello World**" };// 类型守卫if (typeof options.commandline === "function") {console.log(options.commandline());}// hello// Hello// World// **Hello World**
interface namelist {[index: number]: string}var list2: namelist = ["Google", "Runoob", "Taobao"] // 类型一致,正确var list2: namelist = ["Runoob", 1, "Taobao"] // 错误元素 1 不是 string 类型// 报错:不能将类型“number”分配给类型“string”。ts(2322)
interface ages {[key: string]: number}var agelist: ages = {};agelist["runoob"] = 15 // 类型正确agelist[2] = "google" // 类型错误// 报错:不能将类型“string”分配给类型“number”。ts(2322)
- 接口继承就是说接口可以通过其他接口来扩展自己
- ts 允许接口继承多个接口
- ts 接口继承使用关键字
**extends** - 接口继承语法
**<子接口> extends <父接口>**、**<子接口> extends <父接口1>, <父接口2>, ..., <父接口n-1>, <父接口n>** - 接口不会出现在编译结果中
interface Person {age: number}interface Musician extends Person {instrument: string}var drummer = <Musician>{};drummer.age = 27drummer.instrument = "Drums"console.log("年龄: " + drummer.age)console.log("喜欢的乐器: " + drummer.instrument)// 年龄: 27// 喜欢的乐器: Drums
interface IParent1 {v1: number}interface IParent2 {v2: number}interface Child extends IParent1, IParent2 { }var Iobj: Child = { v1: 12, v2: 23 }console.log("value 1: " + Iobj.v1 + " value 2: " + Iobj.v2)// value 1: 12 value 2: 23
