美文网首页
TypeScript 详解之 TypeScript 的 inte

TypeScript 详解之 TypeScript 的 inte

作者: you的日常 | 来源:发表于2023-08-09 18:25 被阅读0次

简介

interface 是对象的模板,可以看作是一种类型约定,中文译为“接口”。使用了某个模板的对象,就拥有了指定的类型结构。

interface Person {
  firstName: string;
  lastName: string;
  age: number;
}

上面示例中,定义了一个接口Person,它指定一个对象模板,拥有三个属性firstNamelastNameage。任何实现这个接口的对象,都必须部署这三个属性,并且必须符合规定的类型。

实现该接口很简单,只要指定它作为对象的类型即可。

const p:Person = {
  firstName: 'John',
  lastName: 'Smith',
  age: 25
};

上面示例中,变量p的类型就是接口Person,所以必须符合Person指定的结构。

方括号运算符可以取出 interface 某个属性的类型。

interface Foo {
  a: string;
}

type A = Foo['a']; // string

上面示例中,Foo['a']返回属性a的类型,所以类型A就是string

interface 可以表示对象的各种语法,它的成员有5种形式。

  • 对象属性
  • 对象的属性索引
  • 对象方法
  • 函数
  • 构造函数

(1)对象属性

interface Point {
  x: number;
  y: number;
}

上面示例中,xy都是对象的属性,分别使用冒号指定每个属性的类型。

属性之间使用分号或逗号分隔,最后一个属性结尾的分号或逗号可以省略。

如果属性是可选的,就在属性名后面加一个问号。

interface Foo {
  x?: string;
}

如果属性是只读的,需要加上readonly修饰符。

interface A {
  readonly a: string;
}

(2)对象的属性索引

interface A {
  [prop: string]: number;
}

上面示例中,[prop: string]就是属性的字符串索引,表示属性名只要是字符串,都符合类型要求。

属性索引共有stringnumbersymbol三种类型。

一个接口中,最多只能定义一个字符串索引。字符串索引会约束该类型中所有名字为字符串的属性。

interface MyObj {
  [prop: string]: number;

  a: boolean;      // 编译错误
}

上面示例中,属性索引指定所有名称为字符串的属性,它们的属性值必须是数值(number)。属性a的值为布尔值就报错了。

属性的数值索引,其实是指定数组的类型。

interface A {
  [prop: number]: string;
}

const obj:A = ['a', 'b', 'c'];

上面示例中,[prop: number]表示属性名的类型是数值,所以可以用数组对变量obj赋值。

同样的,一个接口中最多只能定义一个数值索引。数值索引会约束所有名称为数值的属性。

如果一个 interface 同时定义了字符串索引和数值索引,那么数值索性必须服从于字符串索引。因为在 JavaScript 中,数值属性名最终是自动转换成字符串属性名。

interface A {
  [prop: string]: number;
  [prop: number]: string; // 报错
}

interface B {
  [prop: string]: number;
  [prop: number]: number; // 正确
}

上面示例中,数值索引的属性值类型与字符串索引不一致,就会报错。数值索引必须兼容字符串索引的类型声明。

(3)对象的方法

对象的方法共有三种写法。

// 写法一
interface A {
  f(x: boolean): string;
}

// 写法二
interface B {
  f: (x: boolean) => string;
}

// 写法三
interface C {
  f: { (x: boolean): string };
}

属性名可以采用表达式,所以下面的写法也是可以的。

const f = 'f';

interface A {
  [f](x: boolean): string;
}

类型方法可以重载。

interface A {
  f(): number;
  f(x: boolean): boolean;
  f(x: string, y: string): string;
}

interface 里面的函数重载,不需要给出实现。但是,由于对象内部定义方法时,无法使用函数重载的语法,所以需要额外在对象外部给出函数方法的实现。

interface A {
  f(): number;
  f(x: boolean): boolean;
  f(x: string, y: string): string;
}

function MyFunc(): number;
function MyFunc(x: boolean): boolean;
function MyFunc(x: string, y: string): string;
function MyFunc(
  x?:boolean|string, y?:string
):number|boolean|string {
  if (x === undefined && y === undefined) return 1;
  if (typeof x === 'boolean' && y === undefined) return true;
  if (typeof x === 'string' && typeof y === 'string') return 'hello';
  throw new Error('wrong parameters');  
}

const a:A = {
  f: MyFunc
}

上面示例中,接口A的方法f()有函数重载,需要额外定义一个函数MyFunc()实现这个重载,然后部署接口A的对象a的属性f等于函数MyFunc()就可以了。

(4)函数

interface 也可以用来声明独立的函数。

interface Add {
  (x:number, y:number): number;
}

const myAdd:Add = (x,y) => x + y;

上面示例中,接口Add声明了一个函数类型。

(5)构造函数

interface 内部可以使用new关键字,表示构造函数。

interface ErrorConstructor {
  new (message?: string): Error;
}

上面示例中,接口ErrorConstructor内部有new命令,表示它是一个构造函数。

TypeScript 里面,构造函数特指具有constructor属性的类,详见《Class》一章。

interface 的继承

interface 可以继承其他类型,主要有下面几种情况。

interface 继承 interface

interface 可以使用extends关键字,继承其他 interface。

interface Shape {
  name: string;
}

interface Circle extends Shape {
  radius: number;
}

上面示例中,Circle继承了Shape,所以Circle其实有两个属性nameradius。这时,Circle是子接口,Shape是父接口。

extends关键字会从继承的接口里面拷贝属性类型,这样就不必书写重复的属性。

interface 允许多重继承。

相关文章

网友评论

      本文标题:TypeScript 详解之 TypeScript 的 inte

      本文链接:https://www.haomeiwen.com/subject/tisnpdtx.html