精进TypeScript--你了解类型(type)和接口(interface)的区别吗?

2024-04-04 08:36

本文主要是介绍精进TypeScript--你了解类型(type)和接口(interface)的区别吗?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

要记住的事情:

  • 理解 type 和 interface 之间的异同
  • 知道如何使用其中一种语法来编写相同的类型
  • 当决定在你的项目中使用哪一种语法时,既要考虑既定的风格,也要考虑扩增是否会有好处

如果你想在 TypeScript 中定义一个命名类型,你有两种选择,使用一个类型或接口,如下:

type TState = {name: string;capital: string;
}interface IState {name: string;capital: string;
}

你应该使用哪个?你应该意识到 type 和 interface 之间的区别,并且在哪种情况下使用哪一种都要保持一致。但是,你也应该知道如何使用这两种方式来编写相同的类型,这样你就能自如地读懂使用这两种编写的 TypeScript 代码。

首先,关于相似性:State 类型之间几乎没有区别。不管你用 IState 还是 TState 定义了一个带有多余属性的值,你得到的错误是字对字相同的:

const state: TState = {name: 'China';capital: 'BeiJing';population: 5000000; // ~~ 不能将类型 ... 分配给类型 “TState”
}

你可以对 interface 和 type 使用索引签名:

type TDict = {[key: string]: string};
interface IDict {[key: string]: string;
}

你也可以用它们中的任意一个定义函数类型:

type TFn = (x: number) => string;
interface IFn {(x: number): string;
}const toStrT: TFn = x => '' + x; // OK
const toStrI: IFn = x => '' + x; // OK

对于这种直接的函数类型,类型别名看起来更自然,但如果函数类型也具有属性,那么声明看起来就更相似。

type TFnWithProperties = {(x: number): number;prop: string;
}
interface IFnWithProperties {(x: number): number;prop: string;
}

你可以通过提醒自己,在JavaScript 中,函数是可调用的对象,来记住这种语法。

类型别名和接口都可以是泛型:

type TPair<T> = {first: T;second: T;
}interface IPair<T> = {first: T;second: T;
}

interface 可以扩展 type,type 也可以扩展 interface:

interface IStateWithPop extends TState {population: number;
}
type TStateWithPop = IState & {population: number;}

同样,这两个类型都是相同的。需要注意的是,interface 不能扩展复杂的类型,如联合类型。如果你想这么做,你需要使用 type 和 &。

类(class)可以实现interface或简单类型:

class StateT implements TState {name: string = '';capital: string = '';
}
class StateI implements IState {name: string = '';capital: string = '';
}

这些是相似之处。那不同之处呢?你已经看到了一个:有联合 type,但没有联合 interface:

type A or B = 'a' | 'b';

扩展联合类型是很有用的。如果你有单独的 Input 和 Output 变量的类型,以及从名字(name)到变量的映射:

type Input = { /*...*/ };
type Output = { /*...*/ };
interface VariableMap {[name: string]: Input | Output;
}

那么你可能想要一个将名字(name)附加到变量上的类型,如:

type NamedVariable = (Input | Output) & {name: string};

这个类型无法用 interface 来表达。一般来说,type 比 interface 能力更强。类型可以是一个联合类型,也可以利用更高级的特性,如映射类型(mapped)和条件类型(conditional)。

它还可以更容易地表达元组和数组类型:

type Pair = [number, number];
type StringList = string[];
type NamedNums = [string, ...number[]];

你可以用 interface 来表达类似元组的东西:

interface Tuple {0: number;1: number;length: 2;
}
const t: Tuple = [10, 20]; // OK

但这很笨拙,而且放弃了所有的元组方法,如 concat,所以最好使用 type。

不过,interface 确实有一些 type 没有的能力。其中之一就是 interface 可以被扩增。比如:

interface IState {name: string;capital: string;
}
interface IState {population: number;
}
const state: IState = {name: 'China';capital: 'BeiJing';population: 5000000;
}; // OK

这就是所谓的 “声明合并” ,如果你从来没见过这种写法,它会让你很惊讶。它主要用于类型声明文件,如果你正在编写一个类型声明文件,你就应该遵循该规范,并使用 interface 来支持它。这样做,是因为你的类型声明中可能会缺少一些需要用户补充的属性,这时候用户就会使用声明合并。

对于没有既定风格的项目,你应该考虑扩增。你是否在为一个 API 发布类型声明?如果 API 发生变化时,能够通过 interface 合并新的字段可能对你的用户有帮助,那就使用 interface。但是,对于一个在你项目内部使用的类型,声明合并可能是一个错误,那就倾向于使用 type。

这篇关于精进TypeScript--你了解类型(type)和接口(interface)的区别吗?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/875310

相关文章

MyBatis中$与#的区别解析

《MyBatis中$与#的区别解析》文章浏览阅读314次,点赞4次,收藏6次。MyBatis使用#{}作为参数占位符时,会创建预处理语句(PreparedStatement),并将参数值作为预处理语句... 目录一、介绍二、sql注入风险实例一、介绍#(井号):MyBATis使用#{}作为参数占位符时,会

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

C++中NULL与nullptr的区别小结

《C++中NULL与nullptr的区别小结》本文介绍了C++编程中NULL与nullptr的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编... 目录C++98空值——NULLC++11空值——nullptr区别对比示例 C++98空值——NUL

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

深度解析Spring Boot拦截器Interceptor与过滤器Filter的区别与实战指南

《深度解析SpringBoot拦截器Interceptor与过滤器Filter的区别与实战指南》本文深度解析SpringBoot中拦截器与过滤器的区别,涵盖执行顺序、依赖关系、异常处理等核心差异,并... 目录Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor