Reputation: 923
In below code, Keys of PropertiesNamesInDataBase
must be even with User.Keys
.
The values of PropertiesNamesInDataBase
, as is obviously from name, are being using in backend, but names in frontend must be unified.
namespace User {
export enum Keys {
ID = "ID",
name = "name"
}
}
enum PropertiesNamesInDataBase {
ID = "id",
name = "nm"
}
At least two problems here:
PropertiesNamesInDataBase
is fully independent on User.Keys
, however conceptually PropertiesNamesInDataBase
's keys must refer to User.Keys
by some way.Here is attempt to solve the second problem by referencing of PropertiesNamesInDataBase
keys to User.Keys
:
namespace User {
export enum Keys {
ID = "ID",
name = "name"
}
}
enum PropertiesNamesInDataBase {
[User.Keys.ID] = "id",
[User.Keys.name] = "nm"
}
However it's impossible in TypeScript:
Computed property names are not allowed in enums. (1164)
Please ever tech me how to reuse enum keys, or how to refer PropertiesNamesInDataBase
's keys on User.Keys
's values.
Upvotes: 1
Views: 1795
Reputation: 328433
I'd be inclined to forget about enum
entirely and instead build up your own enum-like objects. This will give you the flexibility you need to write the keys only once, but you will lose some of the built-in expressiveness that comes with enum
(namely that enum Foo {...}
creates both an object named Foo
and a type named Foo
. If you create const Foo = ...
instead, you only get the object, and will need to define your own type yourself if you want it).
Here's one approach:
const KeysAndPropNames = {
ID: { key: "ID", propName: "id" },
name: { key: "name", propName: "nm" }
} as const;
You've got just one object which is a mapping from key to the values you had in your old User.Keys
and PropertiesNamesInDataBase
enums. You can extract those enum-like objects yourself like this:
const User = { Keys: objMapProp(KeysAndPropNames, "key") };
const PropertiesNamesInDataBase = objMapProp(KeysAndPropNames, "propName");
where objMapProp()
is a function you can put in a library that maps a property access over an object:
// library
function objMapProp<T extends Record<keyof T, Record<K, any>>, K extends keyof any>(
obj: T,
key: K
) {
const ret = {} as { [P in keyof T]: T[P][K] };
for (let k in obj) {
ret[k] = obj[k][key];
}
return ret;
}
If you examine the type of the new User
and PropertiesNamesInDataBase
objects with IntelliSense, you'll see they match up to the old values:
/* const User: {
Keys: {
readonly ID: "ID";
readonly name: "name";
};
} */
/* const PropertiesNamesInDataBase: {
readonly ID: "id";
readonly name: "nm";
} */
If you want the types named User.Keys
and PropertiesNamesInDataBase
, you can make them as the union of all the value types of the corresponding objects:
namespace User {
export type Keys = (typeof User.Keys)[keyof typeof User.Keys];
// type User.Keys = "ID" | "name"
}
type PropertiesNamesInDataBase = typeof PropertiesNamesInDataBase[keyof typeof PropertiesNamesInDataBase];
// type PropertiesNamesInDataBase = "id" | "nm"
Anyway, hope that either meets your needs or gives you some idea how to proceed. Good luck!
Upvotes: 1