跳到主要内容

2.3-interface 和 type

Create by fall on 20 Nov 2021 Recently revised in 07 Jan 2023

interface

interface,又叫接口。

接口 interface,可用于对类的一部分进行抽象,也可以用于对象的形状进行描述

用接口来表明定义对象的类型,必须按照所有已定义的类型进行存储,且不能有任何多余。

interface 运行时的影响为 0,因此使用对象进行 extends 操作时,最好使用 interface,能有轻微的性能提升。

基本用法

在同一个作用域下的 interface 会进行合并,因此可能造成一些 bug。

  • 可以使用 readonly 限制接口的属性,被修饰的属性只读。
  • 也可以使用 ? 修饰属性,表明该属性可选。
interface OnePerson{
readonly name:string // 只读属性
age:number
hobby:string
salary?:number // 可选属性
}
let tutou:OnePerson = {
name:'琦玉',
age:33,
hobby:"兴趣使然的英雄"
}
tutou.age = 32
console.log(tutou)

任意属性

使用索引签名方式实现任意属性

// name 属性为必填,其他的键必须为 string
interface Hero{
name:string
[propName:string]:any
}
// 表明该 person 上所有字符串为都是只读的
interface Person {
readonly [x:string]: number
}

注意:一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集

// 错误的写法
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};
// 解决方法
interface Person {
name: string;
age?: number;
[propName: string]: string|number;
}
let tom: Person = {
name: 'Tom',
age: 25,
gender: 'male'
};

函数类型

interface Hero{
(name:string,heroName:string):boolean
}
const tutou = function(name:string,heroName:string):boolean{
// search 作用:返回符合元素的下标,如果为 -1 说明字符串中不存在该数值
return name.search(heroName) > -1
}
console.log(tutou("秃头披风侠","秃头"))

属性检查

属性检查的特点:函数中的一些问题,对比下面的两个例子

// 例一:
interface LabeledValue {
label: string;
}
function printLabel(labeledObj: LabeledValue) {
console.log(labeledObj.label);
}
// 命名一个对象,然后传入该对象
let myObj = { size: 10, label: "Size 10 Object" }
printLabel(myObj); // OK
// 例二:
interface LabeledValue {
label: string;
}
function printLabel(labeledObj: LabeledValue) {
console.log(labeledObj.label);
}
// 直接在方法中传入对象
printLabel({ size: 10, label: "Size 10 Object" }) // Error

区别在一点,如果直接传入对象,是要严格按照 interface 进行实现,如果传入的是引用,则只需实现 interface 的要求即可。这也叫鸭式辨型

类型断言

interface Person {
name: string;
}
function add(x:Person){
console.log(x);
}
add({name:'fdifd',age:11} as Person) // OK
// 同样可以解决

索引签名

interface Props { 
name: string;
age: number;
money?: number;
[key: string]: any;
}
let p: Props = {
name: "兔神",
age: 25,
money: -100000,
girl: false
}; // OK

继承 extends

用类实现 interface

一个类的类型可以通过接口完成约束,并且一个类可以被多个接口进行约束。

接口和接口之间可以继承,类和接口之间称为实现 implements

每一个方法必须都要可以使用

// 定义一个接口
interface OneHero{
hero()
}
// 此时接口可以看做 Person 类的一个约束
class Person implements OneHero{
hero(){
console.log('只有内心强大的人,才有资格做英雄')
}
}
let jodge = new Person
jodge.hero()

多个接口修饰

一个类,同时被多个接口进行修饰

interface OneHero{
hero() // OneHero 限制必须拥有 hero 方法
}
interface TheHero{
action() // TheHero 限制必须拥有 action 方法
}
class Person implements OneHero,TheHero {
hero(){
console.log("一颗执着的心")
}
action(){
console.log("坚定不移的行动")
}
}
let jodge = new Person
jodge.hero()
jodge.action()

接口的泛型

interface Fly<T=string>{
way:T
}
const str:Fly = {way:"airplane"}
const stre:Fly<number> = {way:22}

type

type,又称类型别名

接口和类型别名

什么时候使用 type,什么时候使用 interface?

应该默认使用 type,除非用到 interface 相关的特性,比如 extendsimplements

类型别名会给类型起一个新的名字,有时会和 interface 很像,但是可以做用于原始类型(基本类型),联合类型,元组以及任何手写的类型,并且不会创建新的类型,而是通过这个新名字去引用。

共有特性

// interface 描述对象和函数
interface List{
a:string;
b?:number
}
// 描述一个函数
interface List2{
(name:string,age:number):string
}
// type 描述对象和函数
type List3 ={
a:string;
b?:number
}
// 描述一个函数
type List4 = (x:number,y:string)=>void
type List5 = {// 描述一个可以重载的函数
(a:number):number
(a:string):string
}

扩展,继承

// interface 的继承
interface PointX {
x:number
}
interface Point extends PointX{
y:number
}
// type 的继承
type PointM = {
x:number
}
type PointMN = PointN &{
y:number
}

当然,两者也可以互相进行扩展

// interface 继承 type
type PointX = {x:number}
interface Point extends PointX{ y:number}
// type 继承 interface
interface PointN{ x:number}
type PointMN =PointN &{y:number}

type 特性

类型别名独有的内容

// primitive
type Name = string
// 字面量类型
type Single = 'wangwangwang'
// union 联合类型
type Double = string | number
// tuple 元组
type Data = [number,string]
// dom
let div = document.createElement('div')
type B = typeof div

interface 特性

interface 不能用来表示联合类型

// interface 不能表示以下类型
type Foo = string | number


interface Point {x:number}
interface Point {y:number}
const point:Point = {x:11,y:12}

参考文章

文章名称(作者)链接
阿宝哥https://juejin.cn/post/6844904184894980104
Matt PocockType vs Interface: Which Should You Use?