我正在开发一款金融应用程序,它有"出价"(出价)和"要求"(出价).

interface Ask {
  price: number
  amount: number
}

interface Bid {
  price: number
  amount: number
}

如何避免重复两个相同的类型定义?(它们将始终相同) 我可以只有一个界面,并称之为Offer,但它失go 了意义和清晰度.

我试过这个:

interface Offer {
  price: number
  amount: number
}

interface Bid extends Offer {}
interface Ask extends Offer {}

但是我得到一个eslint错误,说是An interface declaring no members is equivalent to its supertype.,如果我不给它添加一些东西,那么扩展接口就没有意义了.

推荐答案

您可以使用类型别名:

interface Ask {
    price: number;
    amount: number;
}

type Bid = Ask;

Playground link

请注意,因为TypeScrip的类型系统是structural(基于类型的shape),而不是nominative(基于类型的名称/标识),所以类型为Ask的对象将可以赋给Bid个变量/属性/参数,反之亦然.TypeScrip没有区分它们:

let a: Ask = { price: 42, amount: 2 };
//  ^? −−− let a: Ask
let b: Bid = { price: 67, amount: 4 };
//  ^? −−− let b: Ask
a = b; // <== This is allowed

请注意,显示的b类型提示是Ask,而不是Bid.

如果您想区分这两种类型,可以使用Drew Colthorp在文章Flavoring: Flexible Nominal Typing for TypeScript中描述的技术(感谢VLAZ指出这一点;另请参阅Vlaz‘s answer to a related question).它的核心是您可以通过使用optional品牌属性来区分类型,如下所示(但请继续阅读):

interface Offer {
    price: number;
    amount: number;
}

interface Bid extends Offer {
    __type__?: "Bid";
}

interface Ask extends Offer {
    __type__?: "Ask";
}

由于该属性是可选的,因此您不必在创建实例时指定它,但它会使类型彼此不兼容(尽管您可以很容易地从一个类型转换为另一个类型):

let a: Ask = { price: 42, amount: 2 };
//  ^? −−− let a: Ask
let b: Bid = { price: 67, amount: 4 };
//  ^? −−− let b: Bid
a = b; // <== Error: Type 'Bid' is not assignable to type 'Ask'.
       //              Types of property '__type__' are incompatible.
       //                Type '"Bid" | undefined' is not assignable to type '"Ask" | undefined'.(2322)

Playground link

在这篇文章中,Colthorp进一步创建了一个可重用的泛型Flavor类型:

interface Flavoring<FlavorT> {
    _type?: FlavorT;
}
type Flavor<T, FlavorT> = T & Flavoring<FlavorT>;

您将在代码中使用它,如下所示:

interface Offer {
    price: number;
    amount: number;
}

type Bid = Flavor<Offer, "Bid">;

type Ask = Flavor<Offer, "Ask">;

Playground link

ab的相同测试表明,您不能将一个分配给另一个.

最后,您可以通过在实例中实际包含_type(或__type__)属性而不使它们成为可选项来使用全品牌类型.我发现有时这样做很方便,因为我可以在调试器中看到这些属性,并且可以在使用Offer个实例的代码中使用它们来缩小类型范围.但有时您不想让额外的属性弄乱对象,因此采用了上面的"风格"方法.完整的品牌推广示例:

interface Offer {
    price: number;
    amount: number;
}

interface Bid extends Offer {
    __type__: "Bid";
}

interface Ask extends Offer {
    __type__: "Ask";
}

let a: Ask = { price: 42, amount: 2, __type__: "Ask" };
//  ^? −−− let a: Ask
let b: Bid = { price: 67, amount: 4, __type__: "Bid" };
//  ^? −−− let b: Bid
a = b; // <== Error: Type 'Bid' is not assignable to type 'Ask'.
       //              Types of property '__type__' are incompatible.
       //                Type '"Bid"' is not assignable to type '"Ask"'.(2322)

Playground link

Typescript相关问答推荐

类型脚本:类型是通用的,只能索引以供阅读.(2862)"

等待的R没有用响应对象展开到R

当类型断言函数返回假时,TypScript正在推断从不类型

泛型函数中输入参数类型的推断问题

泛型类型联合将参数转换为Never

路由链接不会导航到指定router-outlet 的延迟加载模块

使用打字Angular 中的通用数据创建状态管理

是否可以基于对象的S属性值[]约束对象的其他属性值用于类型化的对象数组?

有没有可能创建一种类型,强制在TypeScrip中返回`tyPeof`语句?

将对象的属性转换为正确类型和位置的函数参数

如何定义这样一个TypeScript泛型,遍历路由配置树并累积路径

在构建Angular 应用程序时,有没有办法通过CLI传递参数?

内联类型断言的工作原理类似于TypeScrip中的断言函数?

完全在类型系统中构建的东西意味着什么?

如何使用useSearchParams保持状态

类型分布在第一个泛型上,但不分布在第二个泛型上

我应该使用服务方法(依赖于可观察的)在组件中进行计算吗?

使用嵌套属性和动态执行时,Typescript 给出交集而不是并集

为什么我的 Typescript 函数中缺少 void 隐式返回类型?

如何在 ngFor 循环中以Angular 正确动态渲染组件