TypeScript 中扩展接口和交叉接口的区别? [英] Difference between extending and intersecting interfaces in TypeScript?

查看:17
本文介绍了TypeScript 中扩展接口和交叉接口的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设定义了以下类型:

interface Shape {
  color: string;
}

现在,请考虑以下方法向此类型添加其他属性:

Now, consider the following ways to add additional properties to this type:

扩展

interface Square extends Shape {
  sideLength: number;
}

交叉口

type Square = Shape & {
  sideLength: number;
}

这两种方法有什么区别?

What is the difference between both approaches?

而且,为了完整性和出于好奇,还有其他方法可以产生可比较的结果吗?

And, for sake of completeness and out of curiosity, are there other ways to yield comparable results?

推荐答案

是的,有些差异可能与您的场景相关,也可能不相关.

Yes there are differences which may or may not be relevant in your scenario.

也许最重要的是在两种类型中出现时具有相同属性键的成员的处理方式不同.

Perhaps the most significant is the difference in how members with the same property key are handled when present in both types.

考虑:

interface NumberToStringConverter {
  convert: (value: number) => string;
}

interface BidirectionalStringNumberConverter extends NumberToStringConverter {
  convert: (value: string) => number;
}

上面的 extends 导致错误,因为派生接口声明了一个与派生接口具有相同键但签名不兼容的属性.

The extends above results in an error because the derriving interface declares a property with the same key as one in the derived interface but with an incompatible signature.

error TS2430: Interface 'BidirectionalStringNumberConverter' incorrectly extends interface 'NumberToStringConverter'.

  Types of property 'convert' are incompatible.
      Type '(value: string) => number' is not assignable to type '(value: number) => string'.
          Types of parameters 'value' and 'value' are incompatible.
              Type 'number' is not assignable to type 'string'.

但是,如果我们使用交集类型

However, if we employ intersection types

type NumberToStringConverter = {
  convert: (value: number) => string;
}

type BidirectionalStringNumberConverter = NumberToStringConverter & {
  convert: (value: string) => number;
}

没有任何错误并进一步给出

There is no error whatsoever and further given

// And this is a good thing indeed as a value conforming to the type is easily conceived
const converter: BidirectionalStringNumberConverter = {
    convert: (value: string | number) => {
        return (typeof value === 'string' ? Number(value) : String(value)) as string & number; // type assertion is an unfortunately necessary hack.
    }
}

const s: string = converter.convert(0); // `convert`'s call signature comes from `NumberToStringConverter`

const n: number = converter.convert('a'); // `convert`'s call signature comes from `BidirectionalStringNumberConverter`

游乐场链接

这导致了另一个有趣的区别,interface 声明是开放式的.可以在任何地方添加新成员,因为在同一声明空间中多个具有相同名称的interface 声明被合并.

This leads to another interesting difference, interface declarations are open ended. New members can be added anywhere because multiple interface declarations with same name in the same declaration space are merged.

这是合并行为的常见用法

Here is a common use for merging behavior

lib.d.ts

interface Array<T> {
  // map, filter, etc.
}

array-flat-map-polyfill.ts

interface Array<T> {
  flatMap<R>(f: (x: T) => R[]): R[];
}

if (typeof Array.prototype.flatMap !== 'function') {
  Array.prototype.flatMap = function (f) { 
    // Implementation simplified for exposition. 
    return this.map(f).reduce((xs, ys) => [...xs, ...ys], []);
  }
}

请注意没有 extends 子句是如何存在的,尽管在单独的文件中指定了接口都在全局范围内,并按名称合并到具有两组成员的单个逻辑接口声明中.(同样可以对语法略有不同的模块范围声明进行)

Notice how no extends clause is present, although specified in separate files the interfaces are both in the global scope and are merged by name into a single logical interface declaration that has both sets of members. (the same can be done for module scoped declarations with slightly different syntax)

相比之下,存储在 type 声明中的交集类型是封闭的,不能合并.

By contrast, intersection types, as stored in a type declaration, are closed, not subject to merging.

有很多很多不同之处.您可以在 TypeScript 手册中阅读有关这两种结构的更多信息.接口高级类型 部分特别相关.

There are many, many differences. You can read more about both constructs in the TypeScript Handbook. The Interfaces and Advanced Types section are particularly relevant.

这篇关于TypeScript 中扩展接口和交叉接口的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆