【问题标题】:How to enforce return all possible keys of type in array [duplicate]如何强制返回数组中所有可能的类型键[重复]
【发布时间】:2020-11-09 00:22:56
【问题描述】:

我有以下类型:

type Fruit = "Banana" | "Melon" | "Apple";

我想创建一个函数来返回Fruit 的所有可能键。比如:

function getAllFruits(): Fruit[] {
  return ["Banana", "Melon"]; // <-- Should throw an error due to missing "Apple".
}

我这样做的原因是我想确保没有人会忘记将以下值添加到数组中。

另一种方法是采用相反的方式 - 创建一个返回所有类型的函数,然后将类型 Fruit 设置为函数的返回类型。无论如何,我对这种方法不感兴趣。

有什么想法吗?

更新 1

我希望看到一个不涉及枚举的解决方案(如果可能的话)。

【问题讨论】:

  • @derpirscher 我有兴趣看到没有枚举的解决方案
  • 为什么不直接使用:type Fruit = ["Banana", "Melon" , "Apple"] ?
  • @captain-yossarian 因为我希望函数值由类型推断,而不是相反。本质上,类型应该决定值应该是什么,而不是函数。

标签: typescript


【解决方案1】:

有两种方法可以解决。

  1. 在编译时生成所有可能的排列。
  2. 创建一个智能身份功能,要求为其提供所有颜色。

第一个解决方案无法扩展。它需要 TypeScript 来生成 n!元组,你很快就会遇到类型系统的限制。这就是我推荐使用第二种方法的原因。

type Fruit = "Banana" | "Melon" | "Apple";

function getAllFruits(): Fruit[] {
  return enumerate<Fruit>()('Apple', 'Banana', 'Melon');
}

助手类型:

type ValueOf<T> = T[keyof T];

type NonEmptyArray<T> = [T, ...T[]]

type MustInclude<T, U extends T[]> =
  [T] extends [ValueOf<U>]
    ? U
    : never;

const enumerate = <T,>() =>
  <U extends NonEmptyArray<T>>(...elements: MustInclude<T, U>) =>
    elements;

Playground

请注意,如果您从getAllFruits 中删除一个水果,编译器会对您大喊大叫。此方法使实现与模型保持同步。

【讨论】:

  • 这真是太好了。一件小事 - 当我从 getAllFruits 中删除一个水果时,我得到的错误不是很有帮助 (Argument of type 'string' is not assignable to parameter of type 'never'.) 有没有解决这个问题的机会?
  • 很好的答案,我学到了很多!谢谢
  • @EliyaCohen 我同意,错误消息根本不提供信息。不幸的是,我还没有找到让它变得更好的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-18
  • 2020-04-08
  • 1970-01-01
  • 2013-03-05
  • 1970-01-01
  • 2014-02-07
  • 2021-07-02
相关资源
最近更新 更多