阅读 125

Interface vs Type Alias

总览


Interface
Type Alias
可用来定义的对象object,array,function,class constructor可以用来表示所有的类型
继承或者扩充性通过 extends 继承通过类型交叉(Intersection Types)扩充
同名合并会同名合并
索引签名“静态索引签名”索引签名无限制
别名type就是用来作为别名来用的。

可用来定义的对象

Interface

1. 定义结构体和数组

interface Person {     name: string;     age: number; } interface Persons {     name: string;     age: number; }[] 复制代码

2. 定义函数

interface Func {   (hour: string, minute: string): boolean; } 复制代码

3. 定义class constructor

interface ClockConstructor {   new (hour: number, minute: number): ClockInterface; } 复制代码

4. 定义混合类型

正如我们之前提到的,接口可以描述现实世界 JavaScript 中存在的丰富类型。 由于 JavaScript 的动态和灵活的特性,您可能偶尔会遇到作为上述某些类型组合工作的对象。 一个这样的例子是一个既作为函数又作为对象的对象,具有附加属性:

interface Counter {   (start: number): string;   interval: number;   reset(): void; } declare let c: Counter c(10); c.reset(); c.interval = 5.0; 复制代码

Type Alias

type这里表达能力拉满,没有什么限制。

1. 定义结构体和数组

type Person = {     name: string;     age: number; } 复制代码

2. 定义函数

type Func = (hour: string, minute: string) => boolean; 复制代码

3.定义 Class constructor

type SomeConstructor = {   new (s: string): SomeObject; }; 复制代码

4. 定义混合类型

type DescribableFunction = {   description: string;   (someArg: number): boolean;   new (s: string): Date; }; 复制代码

其他任何你能想到的type

继承或者扩充性

Interface

interface Shape {   color: string; }   interface PenStroke {   penWidth: number; }   interface Square extends Shape, PenStroke {   sideLength: number; }   let square = {} as Square; square.color = "blue"; square.sideLength = 10; square.penWidth = 5.0; 复制代码

另外interface也可以继承某个class。这是由于class是有类型的。

class Shape {     private color: string } interface PenStroke extends Shape {     penWidth: number; } 复制代码

typescript中class相关内容也是很丰富,更多class相关内容后续单独补充。

Type Alias

type alias没有继承,但可以通过类型交叉来合并多个不同的type或者interface。

interface ErrorHandling {   success: boolean;   error?: { message: string }; } interface ArtistsData {   artists: { name: string }[]; } type ArtworksResponse = ArtworksData & ErrorHandling; 复制代码

如果类型无法交叉,则结果为never

type Never = number & string 复制代码

同名合并

Interface

interface Box {  height: number;  width: number; } interface Box {  weight: number; } let box: Box = {height: 4, with: 5, weight: 6} 复制代码

Interface和同名合并性在一些场景下特别有用。例如使用styled-jsx插件。写 会导致ts报错。这种情况下可以通过扩充React namespace中的StyleHTMLAttributes interface即可保证js不会报错。具体做法是在项目中新增d.ts文件。并且新增如下代码块。

namespace React {   interface StyleHTMLAttributes<T> extends HTMLAttributes<T> {     jsx?: boolean   } } 复制代码

namespace和interface一样也存在同名合并,因此我们实际上是扩充了React namespace中StyleHTMLAttributes interface。

interface继承或者同名合并的情况下 如果存在同名属性类型不兼容或者是属性不符合索引签名,则会报错!

interface Colorful {   color: string; } interface ColorRgb extends Colorful {   opacity: number;   color: number; // error! } 复制代码

interface Colorful {   color: string;   [k: string]: string; } interface Colorful {   brightness: number; // error! } 复制代码

索引签名

Interface

interface中的members或者说是属性得是静态的(static)。不是说interface不支持范型,是interface的属性必须得是固定的。它的索引签名(index signature)必须得是静态的,不支持动态索引。

// 我们可以这么定义interface interface Box<T> {  height: number;  width: number;  weight: T } // 甚至可以这样定义 interface Foo {   [index: number]: number;   [k: `hello-${string}`]: unknown;   // typescript4.4新增特性 } 复制代码

但是下面这种写法在interface中是不合法的。

interface GenericType<T extends string, P> {   [K in T as`get${K}`]: () => P // error! } 复制代码

Type Alias

type alias中对索引签名没有什么限制。可以最大化利用typescript中各种动态模板能力。

type GenericType<T extends string, P> = {   [K in T as`get${Capitalize<K>}`]: () => P } type Hello = GenericType<'hello', number> // getHello: () => number type Foo<T> = {   [index: number]: T;   [k: `hello-${string}`]: unknown; } const a: Foo<number> = {   2: 2333,   'hello-world': {} } 复制代码

别名

Type Alias

字如其名,Type Alias是type别名。可以指代别的type。interface没有这种能力。 例如

type A = number type B = Array<string> interface Obj {   [k: string]: unknown } type C = Obj // 而 interface 没有 “=” 的操作 不能指代其他类型 只有继承 复制代码

小测试

测试1

下面这个代码块会报错,尝试给出正确解释

function foo(param: Record<string, unknown>) { } interface Params {   x: number;   y: string; } declare const a: Params foo(a) 复制代码

答案 TypeScript playground

测试2

还是上面那个代码 我修改一个写法,测试不会报错 给出解释

function foo(param: Record<string, unknown>) { } type Params = {   1: number;   2: string; } declare const a: Params foo(a) 复制代码

答案 TypeScript

总结

Interface 总体来讲还是适合作为“接口”定义,class中用的比较多。其他场景建议一律用Type Alias,遇到的坑和限制会少一些。


作者:Joe_
链接:https://juejin.cn/post/7022130471135871013

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐