mol*_*tar 25 types typescript typescript-generics
鉴于以下情况:
enum FooKeys {
FOO = 'foo',
BAR = 'bar',
}
Run Code Online (Sandbox Code Playgroud)
我想制作一个这样的界面,但不是手动定义键,而是用枚举的值构建它。
interface Foo {
foo: string
bar: string
}
Run Code Online (Sandbox Code Playgroud)
TypeScript 可以实现这样的功能吗?
谢谢!
Fla*_*ken 74
\n\n如何从 TypeScript 中的枚举值构建类型?
\n
枚举可以保存字符串和数字值。
\n对于字符串: \n您可以使用模板字符串从枚举值创建字符串并集
\nenum FooKeys {\n FOO = \'foo\',\n BAR = \'bar\',\n}\n\ntype FooValues =`${FooKeys}`; // this equals \'foo\' |\xc2\xa0\'bar\'\nRun Code Online (Sandbox Code Playgroud)\n对于数字:我们可以以相同的方式创建字符串并集或者:\n从 TS 5.0 开始
\n\n\nTypeScript 5.0 通过为每个计算成员创建\n唯一类型,设法将所有枚举变成联合枚举。这意味着现在可以缩小所有枚举的范围,并将其成员也作为类型引用。
\n
意思是:
\nenum MagicNumbers {\na = 1,\nb = 42\n}\n\nconst numberA : MagicNumbers = 1;\nconst numberB : MagicNumbers = 2; // will raise an error since TS 5.0\n\nRun Code Online (Sandbox Code Playgroud)\n\n对于两者: \n结合以上内容,我们可以构建一个EnumAsUnion类型助手,如下所示
枚举作为union.ts
\ntype StringValues<T> = {\n [K in keyof T]: T[K] extends string ? T[K] : never;\n}[keyof T];\n\ntype NumberValues<T> = {\n [K in keyof T]: T[K] extends number ? T[K] : never;\n}[keyof T];\n\n/**\n * Usage : type EnumValues = EnumAsUnion<typeof anEnum>\n */\ntype EnumAsUnion<T> = `${StringValues<T>}` | NumberValues<T>;\nRun Code Online (Sandbox Code Playgroud)\n例子:
\nimport { EnumAsUnion } from \'enum-as-union\';\n\nenum anEnum {\n val1 = \'a\',\n val2 = \'b\',\n val3 = 1,\n val4 = 2,\n}\n\ntype EnumValues = EnumAsUnion<typeof anEnum>;\n\nlet t: EnumValues;\nt = \'a\';\nt = \'b\';\nt = \'c\'; // error, as expected\n\nt = 1;\nt = 2;\nt = 3; // error, as expected\nRun Code Online (Sandbox Code Playgroud)\n\n
jca*_*alz 43
是的,您可以使用枚举值作为键。您可以使用像标准库这样的映射类型Record<K, V>来防止重复:
enum FooKeys {
FOO = 'foo',
BAR = 'bar',
}
// probably all you need, but it's a type alias
type FooType = Record<FooKeys, string>;
// if you need an interface instead you can do this
interface FooInterface extends FooType {};
Run Code Online (Sandbox Code Playgroud)
您可以验证它是否有效:
declare const foo: FooInterface;
foo.foo; // okay
foo[FooKeys.FOO]; // okay
foo.bar; // okay
foo[FooKeys.BAR]; // okay
foo.baz; // error
Run Code Online (Sandbox Code Playgroud)
那对你有用吗?祝你好运!
[@hackape 的解决方案][1] 很棒,但我发现扩展他的解决方案的重复最少,如下所示:
Run Code Online (Sandbox Code Playgroud)type ReverseMap<T extends Record<keyof T, any>> = { [V in T[keyof T]]: { [K in keyof T]: T[K] extends V ? K : never; }[keyof T]; } const Map = { 'FOO': "foo" as "foo", 'BAR': "bar" as "bar", } const reverseMap: ReverseMap<typeof Map> = Object.entries(Map).reduce((rMap, [k, v]) => { rMap[v] = k; return rMap; }, {} as any); export type Values = keyof typeof reverseMap; // 'foo' | 'bar';[此处][2]很好地解释了 ReverseMap 的实现
[1]: https: //stackoverflow.com/a/60768453/5519365 [2]: /sf/answers/3864662021/
更新:我找到了一个更简单的 ReverseMap 解决方案
const Obj = {
FOO: 'foo',
BAR: 'bar',
} as const;
type ReverseMap<T> = T[keyof T];
export type Values = ReverseMap<typeof Obj>; // 'foo' | 'bar';
Run Code Online (Sandbox Code Playgroud)
这回答了你的问题了吗?
enum FOO_BAR {
F = "foo",
B = "bar",
}
type FooType = Record<FOO_BAR, string>;
const obj: FooType = {
// you can use enum values, better for refactoring
[FOO_BAR.F]: "action foo",
[FOO_BAR.B]: "action bar",
// or use enum values
// foo: "action foo",
// bar: "action bar",
};
obj[FOO_BAR.F]; // -> "action foo"
obj["foo"]; // -> "action foo"
// If you want partial keys
type FooTypePartial = Partial<FooType>;
const objPartial: FooTypePartial = {
[FOO_BAR.F]: "action foo",
};
objPartial["foo"]; // -> "action foo", may be undefined
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
15975 次 |
| 最近记录: |