typeScript 接口(interface)及其与类型别名(type)的区别
接口在typeScript中是用来定义对象的类型,对于没有其他语言基础,又刚入门typeScript的同学,可能刚开始觉得接口概念很简单,深入之后又觉得揉杂,本文作者结合自己的学习体验来介绍TypeScript中接口的基本概念及其使用方法。
1.接口基本概念
接口在ts中使用interface来定义,首先看一个最简单示例:
最简单的例子
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
这个例子定义了一个接口Person,接着定义了一个变量tom,他的类型是Person,约束了tom的形状必须和接口Person保持一致。如果变量tom中多一些属性,少一些属性,都是不可以的。
可选属性
当存在某些属性,我们希望灵活生成的对象灵活匹配的时候,可以使用可选属性?:
interface Person {
name: string;
age?: number; // 可选属性
}
let tom: Person = {
name: 'Tom',
age: 25
};
let lee: Person = {
name: 'Lee'
}
任意属性
有时候我们希望一个接口允许有任意的属性,可以使用任意属性[propName: string]
interface Person {
name: string;
age?: number;
[propName: string]: string | number | undefined; // 任意属性
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
只读属性
某些字段只希望在对象创建的时候被赋值,那么可以用 readonly
定义只读属性:
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
id: 89757,
name: 'Tom',
gender: 'male'
};
比如上图中的readonly,如果通过tom.id = xx的方式去修改,则会报错。
注意 只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候:
2.接口的使用
普通对象类型
interface Person {
name: string;
age: number;
}
let tom: Person = {
name: 'Tom',
age: 25
};
函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(src, sub) {
let result = src.search(sub)
}
可索引类型
比如数组也可以使用接口去定义类型,但是不推荐这么使用
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
混合类型
一个对象可以同时作为函数和对象使用,并带有额外的属性
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
- 类与接口的几个问题
接口继承接口
interface Shape {
color: string
}
interface Heigh {
height: number
}
interface Square extends Shape,Heigh {
width: number
}
// let mySquare: Square = {}
let mySquare = <Square>{}
mySquare.color = 'ss'
mySquare.width = 12
mySquare.height = 22
类实现接口
interface Alarm {
alert(): void;
}
class Door {
}
class SecurityDoor extends Door implements Alarm {
alert() {
console.log('SecurityDoor alert');
}
}
class Car implements Alarm {
alert() {
console.log('Car alert');
}
}
接口继承类
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
为什么 TypeScript 会支持接口继承类呢?
实际上,当我们在声明 class Point
时,除了会创建一个名为 Point
的类之外,同时也创建了一个名为 Point
的类型(实例的类型)。
所以我们既可以将 Point
当做一个类来用(使用 new Point
创建它的实例),
也可以将 Point
当做一个类型来用(使用 : Point
表示参数的类型):
- 声明
Point
类时创建的Point
类型只包含其中的实例属性和实例方法
接口的合并
interface User {
name: string
}
interface User {
age: number
}
会合并成为一个接口
interface User {
name: string
age: number
}
3.interface与type的异同点
初学interface与type时,总会搞混这两个概念,很多功能两者都可以实现,这里再区分一下两者的异同:
- interface 接口,主要的作用是定义对象、函数等的结构类型;
- type 类型别名,可以用来给类型起一个新名字;
相同点:
都可以描述对象和函数
- interface
interface myObj {
name: string
age: number
}
interface myFunc {
(name: string): void
}
- type
type myObj = {
name: string,
age: number
}
type myFunc = {
(name: string): void
}
都允许扩展
- interface
interface Area {
width: number
height: number
}
interface Picture extends Area {
color: string
}
- type
type Area = {
width: number
height: number
}
type Picture = Area & { color: string }
不同点
- type 可以声明基本类型别名,
联合类型
,字符串字面量
,元组,获取实例类型
type Name = string;
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
} else {
return n();
}
}
type PetList = [string, number]
type normalColor = 'red' | 'green' | 'black'
// 获取实例类型
type myObj = {
name: string,
age: number
}
let mineObj: myObj = {
name: '2w',
age: 12
}
type anotherObj = typeof mineObj
- interface 可以声明合并
interface User {
name: string
}
interface User {
age: number
}
会合并成为一个接口
interface User {
name: string
age: number
}
转载自:https://juejin.cn/post/7147575342163738638