Typescript:从联合类型中排除一个被其他类型扩展的类型

3

我有一个联合类型,如下所示:

export type TileType =
      | ProductTileType
      | CustomTileType
      | DealTileType
      | LoadingTileType

有一个需要能够接受 ProductTileType | CustomTileType | DealTileType 类型的属性的 React 组件。因此,我使用类型 Exclude<TileType, LoadingTileType> 声明了该属性,以防止在此处使用该类型。唯一的问题是 ProductTileType 的声明如下:

export interface ProductTileType extends LoadingTileType { ... }

当我排除 LoadingTileType 时,TS 还想要排除任何继承它的类型。我如何避免排除我想要排除的类型的扩展?是否还有其他我不知道的实用类型? 编辑: type MyType = Exclude<TileType, LoadingTileType> | ProductTileType 将是解决手头问题的快速解决方法(在这种情况下,ProductTileType 是唯一继承 LoadingTileType 的类型)。但是在未来可能会有其他类型扩展 LoadingTileType。有更好的处理方式吗?

没事了,我想出来了 type MyType = Exclude<TileType, LoadingTileType> | ProductTileType; - Andrew Allison
1
这并不是最理想的解决方案,因为如果你再次扩展 LoadingTileType,你还需要在这里添加新成员。但如果它能解决你的问题,那么请随意回答你自己的问题。 - zenly
在这种情况下,ProductTileType是唯一一个扩展LoadingTileType的。但你说得对,在未来可能会有其他类型。有什么更好的处理方式吗?我会更新问题。 - Andrew Allison
LoadingTileType作为TileType是否有意义呢?caTS的回答在技术层面上是可行的,但如果LoadingTileType是某种模板而独立存在没有意义(就像他们示例中的soda),也许你应该将其删除。例如,假设caTS想要添加一种柠檬水品牌,那么在Drinks中保留Lemonade仍然有意义吗?也许应该包含MyBrandLemonade和一个新的衍生品——HomeMadeLemonade。这样,你就有了2种特定类型的LemonadeDrinks中,而没有通用的。当需求改变时,领域模型也会跟着改变。 - geoffrey
在我的情况下,LoadingTileType既是可以包含在联合类型中的有效接口,也是可以被联合类型中的另一个接口扩展的有效接口。我知道@caTS提供的Soda示例在实际应用中没有意义,但它背后的理论解决了我LoadingTileType接口所提出的问题。 - Andrew Allison
1个回答

3

假设我们有一些饮料:

interface Water { healthiness: 1000 }
interface Lemonade { healthiness: 500 }
interface Tea { healthiness: 1250 } // really it depends on what kind of tea

interface Soda { healthiness: -1000 }
interface Coke extends Soda { fizziness: 1000 }
interface DrPepper extends Soda { fizziness: 800 }
interface Pepsi extends Soda { fizziness: 750 }

type Drinks = Water | Lemonade | Tea | Soda | Coke | DrPepper | Pepsi;

现在,我需要一个类型包含所有饮品,但排除极不具体的"Soda"饮料。
虽然我可以排除它,然后再返回其他更具体的苏打水:
type NoGenericSodaBad = Exclude<Drinks, Soda> | Coke | DrPepper | Pepsi;

我需要的是更严格的“排除”功能:Exclude
type StrictExclude<T, U> = T extends U ? U extends T ? never : T : T;

这种类型排除了 U,只保留 U(虽然如果传入never,它肯定会破坏一些东西),因为联合类型的每个成员 T 必须是可相互赋值的到 U。这意味着我可以不用“苏打水”就能拿到我的饮料!

type NoGenericSodaGood = StrictExclude<Drinks, Soda>;

Playground


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接