TypeScript 中 interface 和 type 的区别,你真的懂了吗?

类型别名 type

首先认识一下什么是的懂类型别名?

类型别名用来给一个类型起个新名字,使用 type 创建类型别名,区别类型别名不仅可以用来表示基本类型,的懂还可以用来表示对象类型、区别联合类型、的懂元组和交集。区别让我们看一些例子:

type userName = string; // 基本类型

type userId = string | number; // 联合类型

type arr = number[];

// 对象类型

type Person = {

id: userId; // 可以使用定义类型

name: userName;

age: number;

gender: string;

isWebDev: boolean;

};

// 范型

type Tree= { value: T };

const user: Person = {

id: "901",的懂

name: "椿",

age: 22,

gender: "女",

isWebDev: false,

};

const numbers: arr = [1, 8, 9];

接口 interface

接口是命名数据结构(例如对象)的另一种方式;与type 不同,interface仅限于描述对象类型。区别

接口的的懂声明语法也不同于类型别名的声明语法。让我们将上面的区别类型别名 Person 重写为接口声明:

interface Person {

id: userId;

name: userName;

age: number;

gender: string;

isWebDev: boolean;

}

interface和type的相似之处

在讨论二者区别之前, 首先看一下二者的的懂相似之处(为何开发中,我们觉得用哪个都一样)

都可以描述 Object和Function

两者都可以用来描述对象或函数,区别但语法不同:

Type type Point = {

x: number;

y: number;

};

type SetPoint = (x: number, y: number) => void;

Interface

interface Point {

x: number;

y: number;

}

interface SetPoint {

(x: number, y: number): void;

}

二者都可以被继承

interface 和 type 都可以继承。

另一个值得注意的的懂是,接口和类型别名并不互斥。区别类型别名可以继承接口,的懂反之亦然。云服务器提供商只是在实现形式上,稍微有些差别。

interface 继承 interface interface Person{

name:string

}

interface Student extends Person { stuNo: number }

interface 继承 type type Person{

name:string

}

interface Student extends Person { stuNo: number }

type 继承 type type Person{

name:string

}

type Student = Person & { stuNo: number }

type 继承 interface interface Person{

name:string

}

type Student = Person & { stuNo: number }

实现 implements

类可以实现interface 以及 type(除联合类型外)

interface ICat{

setName(name:string): void;

}

class Cat implements ICat{

setName(name:string):void{

// todo

}

}

// type

type ICat = {

setName(name:string): void;

}

class Cat implements ICat{

setName(name:string):void{

// todo

}

}

上面提到了特殊情况,类无法实现联合类型, 是什么意思呢?

type Person = { name: string; } | { setName(name:string): void };

// 无法对联合类型Person进行实现

// error: A class can only implement an object type or intersection of object types with statically known members.

class Student implements Person {

name= "张三";

setName(name:string):void{

// todo

}

}

上面聊了interface与 type的相似之处, 接下来就来看看他们的区别。

二者区别

1. 定义基本类型别名

type可以定义基本类型别名, 但是interface无法定义,如:

type userName = string

type stuNo = number

...

2. 声明联合类型

type可以声明联合类型, 例如:

type Student = { stuNo: number} | { classId: number}

3. 声明元组

type可以声明 元组类型:

type Data = [number, string];

以上都是 type能做到, 而interface做不到的, 接下来聊聊type做不到的

4. 声明合并

如果你多次声明一个同名的接口,TypeScript 会将它们合并到一个声明中,并将它们视为一个接口。这称为声明合并, 例如:

interface Person { name: string }

interface Person { age: number }

let user: Person = {

name: "Tolu",

age: 0,

};

这种情况下,如果是type的话,重复使用Person是会报错的:

type Person { name: string };

// Error: 标识符“Person”重复。ts(2300)

type Person { age: number }

5. 索引签名问题

如果你经常使用TypeScript, 一定遇到过相似的错误:

Type xxx is not assignable to type yyy

Index signature is missing in type xxx.

看个例子来理解问题:

interface propType{

[key: string] : string

}

let props: propType

type dataType = {

title: string

}

interface dataType1 {

title: string

}

const data: dataType = { title: "订单页面"}

const data1: dataType1 = { title: "订单页面"}

props = data

// Error:类型“dataType1”不可分配给类型“propType”; 类型“dataType1”中缺少索引签名

props = data1

我们发现dataType和dataType1对应的类型一样,但是interface定义的就赋值失败,站群服务器是什么原因呢?刚开始百思不解,最后我在 stack overflow上找到了一个相似的问题:

image.png

并且很幸运的找到了有效的答案:

image.png

翻译过来的大致意思就是:

Record<string,string>与{ [key:string]:string}相同。只有当该类型的所有属性都已知并且可以对照该索引签名进行检查时,才允许将子集分配给该索引签名类型。在您的例子中,从exampleType到Record<string,string>的所有内容都是可分配的。这只能针对对象字面量类型进行检查,因为一旦声明了对象字面量类型,就无法更改它们。因此,索引签名是已知的。

相反,在你使用interface去声明变量时,它们在那一刻类型并不是最终的类型。由于interfac可以进行声明合并,所以总有可能将新成员添加到同一个interface定义的类型上。

再结合

源码库
IT科技类资讯
上一篇:个人域名转为公司需要什么条件?个人域名转为公司该怎么做?
下一篇:什么样的邮箱才是安全的电子邮件地址?