【问题标题】:Typescript: string literal union type from enum打字稿:来自枚举的字符串文字联合类型
【发布时间】:2019-02-22 21:53:51
【问题描述】:

我想从一个枚举中得到一个字符串文字联合。

对于这个枚举…

enum Weekday {
    MONDAY = 'mon',
    TUESDAY = 'tue',
    WEDNESDAY = 'wed'
}

…我想要这个:

type WeekdayType = 'mon' | 'tue' | 'wed';

我尝试了typeof keyof Weekday,但结果是'MONDAY' | 'TUESDAY' | 'WEDNESDAY'。感觉解决方案可能与映射类型有关,但我似乎无法理解它。

我该怎么做?

【问题讨论】:

  • 很遗憾,您不能这样做。 (有关更多信息,请参阅this related question)。
  • 太不幸了!

标签: typescript enums


【解决方案1】:

TS4.1 ANSWER:

type WeekdayType = `${Weekday}`;

TS-4.1 之前的答案:

这不能以编程方式完成...您正在尝试将类型 Weekday(即 Weekday.MONDAY | Weekday.TUESDAY | Weekday.WEDNESDAY)转换为类型 WeekdayType(即 "mon" | "tue" | "wed")。这种转换是一种加宽的形式,因为WeekdayWeekdayType的子类型:

type WeekdayExtendsWeekdayType = 
  Weekday extends WeekdayType ? true : false
// type WeekdayExtendsWeekdayType = true

不幸的是,编译器没有给你一个句柄来从枚举类型中删除“枚举”-ness 并留下纯文字类型。


那么,解决方法?也许您实际上并不需要enum,但可以使用属性值为字符串文字的对象:

const lit = <V extends keyof any>(v: V) => v;
const Weekday = {
  MONDAY: lit("mon"),
  TUESDAY: lit("tue"),
  WEDNESDAY: lit("wed")
}
type Weekday = (typeof Weekday)[keyof typeof Weekday],

如果您检查它,名为 Weekday 的行为就像一个枚举对象:

console.log(Weekday.TUESDAY); // tue

而名为Weekday类型 的行为类似于您调用的"mon" | "tue" | "wed" 字符串值的联合WeekdayType

const w: Weekday = "wed"; // okay
const x: Weekday = "xed"; // error

因此,在此解决方法中,没有“枚举”-ness,因此无需区分类型 Weekday 和类型 WeekdayType。它与实际的 enum 有点不同(其中包括 types,例如 Weekday.MONDAY,您必须将其表示为繁琐的 typeof Weekday.MONDAY 或为其创建不同的类型别名),但是它的行为可能足够相似以至于有用。这对你有用吗?

希望对您有所帮助。祝你好运!

【讨论】:

  • 更新:从 typescript 3.4 开始,不再需要特殊的 lit 函数。你可以改用const assertions
  • 古玩问题@jcalz。 &lt;V extends keyof any&gt; 是做什么的?它可以防止扩大任何类型的字符串/数字文字?谢谢!
  • 有没有相反的方法?从字符串文字联合的类型中获取字符串枚举?
  • @Pablo 我不这么认为。
【解决方案2】:

TypeScript 4.1+:

As mentioned,这可以通过使用模板文字类型来实现,如下所示:

type WeekdayType = `${Weekday}`;

TypeScript 3.4+:

跟进@jcalz 的回答和@just-boris 的评论,这里有一个带有 const 断言的示例:

const Weekday = {
  MONDAY: "mon",
  TUESDAY: "tue",
  WEDNESDAY: "wed",
} as const;

type Weekday = (typeof Weekday)[keyof typeof Weekday];

编辑:

为想要深入挖掘的人写了blog post

【讨论】:

  • 天哪,谢谢。我挣扎了好几个小时试图弄清楚这一点。
  • 应该可以,但有一个限制。 ``` type Weekday1 = (typeof Weekday)[keyof typeof Weekday];类型 Weekday2 = ${Weekday}; const day1: Weekday1 = Weekday.MONDAY; => 作品 const day2: Weekday2 = Weekday.MONDAY; => 工作 const day3: Weekday1 = 'mon' => 不工作 const day4: Weekday2 = 'mon'; => 工作 ```
【解决方案3】:

有了Typescript 4.1,就可以搞定!

enum Weekday {
  MONDAY = 'mon',
  TUESDAY = 'tue',
  WEDNESDAY = 'wed'
}

type WeekdayType = `${Weekday}`;

警告:这仅适用于字符串枚举值,不适用于数字枚举值。

【讨论】:

  • 更简单的方法是:输入 WeekdayUnion = ${Weekday};就是这样!
  • 运气好可以用 ts-node 编译吗?
  • @MichaelG 是的,您只需在开发依赖项中的项目 package.json 中将您的 typescript 版本更新为 4.1
  • 有人可以为这种行为提供文档吗?!
猜你喜欢
  • 2018-04-28
  • 2022-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-08
  • 2018-10-23
相关资源
最近更新 更多