Reputation: 3221
enum
as a key to an object in an interface?I wrote the snippet bellow to test if is (or isn't) possible.
export enum colorsEnum{
red,blue,green
}
export interface colorsInterface{
[colorsEnum.red]:boolean,
[colorsEnum.blue]:boolean,
[colorsEnum.green]:boolean
}
However, When I run the snippet, an error occurs that prints the following message:
A computed property name in an interface must directly refer to a built-in symbol.
I'm doing it wrong, or is it simply just not possible?
Upvotes: 99
Views: 102198
Reputation: 18966
Probably you are searching for key remapping via as
.
Note: Requires TypeScript ^4.1.
Example:
enum Color {
red,
blue,
green,
}
// Define valid colors
// type TColor = 'red' | 'blue' | 'green';
type TColor = keyof typeof Color;
// Define object structure, with `color` as prefix for each `TColor`
type TWithColorCode = {
[colorKey in TColor as `color${Capitalize<string & colorKey>}`]: string;
};
const a: TWithColorCode = {
// All properties will be required
colorGreen: '#00FF00',
colorBlue: '#0000FF',
colorRed: '#FF0000',
};
// Extending an `interface`:
export interface ICarRGB extends TWithColorCode {
id: number;
name: string;
// Optional property
createdAt?: Date;
}
const b: ICarRGB = {
id: 1,
name: 'Foo',
colorGreen: '#00FF00',
colorBlue: '#0000FF',
colorRed: '#FF0000',
};
Upvotes: 4
Reputation: 241
A simple solution using the native Record<Keys, Type>
utility. (Docs)
export enum Colors {
RED = 'red',
GREEN = 'green',
BLUE = 'blue'
}
export type ColorInterface = Record<Colors, boolean>
This type translates to:
// translates to:
export type ColorInterface = {
red: boolean;
green: boolean;
blue: boolean;
}
IMPORTANT: You must to define an enum
key and map the values accordingly to them, else, you'll get a type / interface that uses an enum's index
like the following:
export enum Colors {
'red',
'green',
'blue'
}
export type ColorInterface = Record<Colors, boolean>
// translates to:
export type ColorInterface = {
0: boolean;
1: boolean;
2: boolean;
}
Alternatively, you can also define the Colors using type
alias if you don't want to explicitly define the enum keys or if you have just a few keys to use, this will also translate properly to what you need:
export type Colors = 'red' | 'green' | 'blue'
// will also translate to:
export type ColorInterface = {
red: boolean;
green: boolean;
blue: boolean;
}
Upvotes: 24
Reputation: 1440
This worked for us:
type DictionaryFromEnum = {
[key in keyof typeof SomeEnum]?: string
}
Upvotes: 12
Reputation: 4081
Why not to keep it as simple as it should be:
export enum Color {
Red = 'red',
Blue = 'blue',
Green = 'green'
}
export interface IColors{
[Color.Red]: boolean,
[Color.Blue]: boolean,
[Color.Green]: boolean
}
Upvotes: 8
Reputation: 2520
OK, the key idea is to convert the Enum to the correct Type and to extends the Interface with it: You can check it out in live code here.
const enum Enum {
key1 = "value1",
key2 = "value2",
key3 = "value3",
}
type EnumKeys = keyof typeof Enum;
type EnumKeyFields = {[key in EnumKeys]:boolean}
interface IEnumExtended extends EnumKeyFields {
KeyEx1:boolean;
KeyEx2:string;
}
// Test it
const enumInstance: IEnumExtended = {
};
when you inside the enumInstance
you will get autocomplete for the Enum keys and not the values.
Upvotes: 41
Reputation: 1339
You can try with type:
export enum colorsEnum{
red, blue, green
}
export type colorsInterface = {
[key in colorsEnum]: boolean;
};
let example: colorsInterface = {
[colorsEnum.red]: true,
[colorsEnum.blue]: false,
[colorsEnum.green]: true
};
Or if you do not want to use all keys: add a ?
export type colorsInterface = {
[key in colorsEnum]?: boolean;
};
let example: colorsInterface = {
[colorsEnum.red]: true,
[colorsEnum.blue]: false
};
Upvotes: 123
Reputation: 251022
To define an interface, the member names must be supplied not computed.
export interface colorsInterface {
red: boolean;
blue: boolean;
green: boolean;
}
If you are worried about keeping the enum and the interface in sync you could use the following:
export interface colorsInterface {
[color: number]: boolean;
}
var example: colorsInterface = {};
example[colorsEnum.red] = true;
example[colorsEnum.blue] = false;
example[colorsEnum.green] = true;
TypeScript is perfectly happy for you to pass the enum as the index and a rename-refactor would then keep everything together if you decided to rename red
, for example.
Upvotes: 23