我有一个像这样的枚举:
export enum ApiFunctions {
"setHidden" = "HIDE",
"setReadOnly" = "SET_READ_ONLY",
"setVisible" = "SHOW",
"setDescription" = "SET_DESCRIPTION",
"setName" = "SET_NAME",
"makeRequest" = "MAKE_REQUEST"
}
今天早些时候,我从此枚举中创建了一种新类型:
export type ApiActions = Exclude<`${ApiFunctions}`, "MAKE_REQUEST">
类型返回键的所有值,除了“ make_request”(set_description,....)。
此 TS 4.1和当前的Bundler的TS版本为3.9.7,由于外部提供,我无法真正对其进行更新。
我尝试通过执行以下操作来复制此类型:
export type Something = Exclude<typeof ApiFunctions[keyof typeof ApiFunctions], "MAKE_REQUEST">
但是这种类型而不是给我每个键 set_name |的实际字符串值| set_description ...
在 apiftunctions.setname的行中给我一些东西| apiftunctions.setDescription ...
是否有一种方法可以以其他方式实现模板文字创建的类型完全相同?
I have an enum like so:
export enum ApiFunctions {
"setHidden" = "HIDE",
"setReadOnly" = "SET_READ_ONLY",
"setVisible" = "SHOW",
"setDescription" = "SET_DESCRIPTION",
"setName" = "SET_NAME",
"makeRequest" = "MAKE_REQUEST"
}
Earlier today I created a new type from this enum like so:
export type ApiActions = Exclude<`${ApiFunctions}`, "MAKE_REQUEST">
This type returns all the values of the keys except "MAKE_REQUEST" (SET_DESCRIPTION,....)
The problem is Template literal types were released on ts 4.1 and the current bundler's ts version is 3.9.7 and I can't really update it since it is externally provided.
I have tried replicating this type by doing:
export type Something = Exclude<typeof ApiFunctions[keyof typeof ApiFunctions], "MAKE_REQUEST">
But this type instead of giving me the actual string value of each key SET_NAME | SET_DESCRIPTION ...
gives me something in the lines of ApiFunctions.setName | ApiFunctions.setDescription ...
Is there a way of achieving exactly the same type created by the template literal on any other way?
发布评论
评论(1)
不,在打字稿4.1之前,没有程序化方法可以扩展 types 对相应的字符串字面类型。
但是,您可能不想做这样的事情(即使使用Typescript 4.1及以上),并且可能有更好的方法。 TypeScript
enum
s最适合其值 opaque 到您的打字稿代码库的情况。因此,除了enum
定义本身之外,您的代码不应关心其特定值。您应该访问这些值的唯一方法是通过枚举。因此,始终apiftunctions.sethiddend
,从不“ hide”
。这意味着您应该能够更改thexcript代码内部的值,并且不应破坏。当然,如果这些值对某些外部系统(例如API)很重要,那么与该系统的通信将不再起作用。但是相反,如果外部系统更改,以便它想要
“隐藏”
而不是“ hide”
,那么您唯一必须在TS代码中更改的是sethidden =“隐藏”
;您不需要进行“ hide”
字符串字面的全局查找,并使用“隐藏”
文字。毕竟,如您所见,编译器并不容易参考枚举的字面价值。它的观点是,
apiftunctions.sethiddend
是比“ hide”
更具体,因此您不能使用类型“ hide” ,其中需要类型
apiftiftions.SETHIDDER
的值。与编译器与编译器作斗争是为了获得可疑利益而付出了很多努力。如果可能的话,让枚举保持枚举。考虑到这一点,我对
apiactions
的建议将是:另一方面,如果您的打字稿代码真的确实关心 可能不适合您的用例。由于Typescript 3.4引入断言,获得类似枚举的对象。看起来这样:
由此可以通过编程方式制作也称为
apiftunctions
:这两个定义与
apiftunctions
的枚举版本相似,除了现在编译器让您通过枚举参考值作为字面类型:哪种方法(如果有的话)对您有利,取决于您的用例。我倾向于避免
Enum
在任何地方都完全避免,因为它们不属于JavaScript,并且具有令人惊讶的行为(尤其是数字枚举)。但这是个人偏爱。Playground link to code
No, before TypeScript 4.1 there was no programmatic way to widen string
enum
types to their corresponding string literal types.However, you probably shouldn't want to do such a thing (even with TypeScript 4.1 and above) and there might be a better approach. TypeScript
enum
s are most appropriate for situations where their values are opaque to your TypeScript code base. So other than theenum
definition itself, your code should not care about their specific values. The only way you should access these values is through the enum. So alwaysApiFunctions.setHidden
and never"HIDE"
.That means you should be able to change the values and nothing inside the TypeScript code should break. Of course, if those values are important to some external system like an API, then communication with that system would no longer work. But conversely, if the external system changes so that it wants
"CONCEAL"
instead of"HIDE"
, the only thing you should have to change in your TS code issetHidden = "CONCEAL"
; you shouldn't need to do a global find-and-replace of the"HIDE"
string literal with the"CONCEAL"
literal.After all, as you've seen, the compiler doesn't make it easy to refer to the literal values of an enum. It takes the view that
ApiFunctions.setHidden
is more specific than"HIDE"
, and so you can't use a value of type"HIDE"
where a value of typeApiFunctions.setHidden
is required. And fighting with the compiler to produce one from the other is a lot of effort for questionable benefit. Let enums stay enums, if at all possible.With that in mind, my suggestion for
ApiActions
would be:On the other hand, if your TypeScript code really does care about the specific string literal types, then
enum
might not be right for your use case. Since TypeScript 3.4 introducedconst
assertions, it's been pretty easy to get an enum-like object. It looks like this:From this you can programmatically make a union type also called
ApiFunctions
:These two definitions behave similarly to the enum version of
ApiFunctions
, except now the compiler lets you refer to the values both through the enum and as literal types:Which approach, if any, works better for you depends on your use case. I tend to avoid
enum
s entirely wherever I can, because they're not part of JavaScript, and they have surprising behavior (especially numeric enums). But that's personal preference.Playground link to code