dwjohnston
dwjohnston

Reputation: 11870

Using an enum to define a list of keys on an interface

I want create a interface that has a dynamic list of keys, that are based on the values of an enum.

Basically, it would look something like this:

enum MyEnum {
    foo = "foo", 
    bar ="bar"
}

interface MyInterface {  //A generic on this line
    id: string; 
    objects: {
        [key: string] : string;   //Instead of mapping to string,
                                  // map to the values of the enum
    }
}

const x : MyInterface<MyEnum> = {
    id: "123", 
    objects: {
        foo: "hello", 
        bar: "world", 
    }
}

//Now I can access the values with: 
console.log(x.objects[MyEnum.foo]); 

const y : MyInterface<MyEnum> = {
    id: "123", 
    objects: {
        foo: "hello", //Should give typeScript warning - bar doesn't exist. 
    }
}

There are two things I don't know how to do here.

  1. How do I define that a generic must be an enum type?
  2. How would I do the dynamic keys list for the generic enum?

I'm happy to not use enums specifically if there is a handy solution that will do this.

Related reading:

This Typescript github issue: https://github.com/microsoft/TypeScript/issues/13042

If the answer is - 'This is not possible as...' can you please give a link to the best Github issue discussion(s) - and a summary of what the resolutions were? From the reading I have seen, this is a feature that a lot of people want.

Update: My current best solution involves creating an interface as the pseudo enum definition, and an implementation of that enum. Playground here. I'm not very happy with though.

Upvotes: 1

Views: 1119

Answers (1)

Raja Jaganathan
Raja Jaganathan

Reputation: 36147

You can try with Type like below, also modified object type to Record<k,T>

type MyEnum = "foo" | "bar";

interface MyInterface<K extends MyEnum, T> {
    id: string;
    objects: Record<K, T>;
}

const x: MyInterface<MyEnum, string> = {
    id: "123",
    objects: {
        foo: "hello",
        bar: "world"
    }
};

//Now I can access the values with:
console.log(x.objects.notAvailable); // Property 'notAvailable' does not exist on type 'Record<MyEnum, string>'
console.log(x.objects.foo); //ok

const y: MyInterface<MyEnum, string> = {
    id: "123",
    objects: {
        foo: "hello" //Should give typeScript warning - bar doesn't exist.
    }
};

(or) with Enum

enum MyEnum {
    "foo" = "foo",
    "bar" = "bar"
}

interface MyInterface<K extends MyEnum, T> {
    id: string;
    objects: Record<K, T>;
}

const x: MyInterface<MyEnum, string> = {
    id: "123",
    objects: {
        foo: "hello",
        bar: "world"
    }
};

//Now I can access the values with:
console.log(x.objects.notAvailable); // Property 'notAvailable' does not exist on type 'Record<MyEnum, string>'
console.log(x.objects.bar); //ok

const y: MyInterface<MyEnum, string> = {
    id: "123",
    objects: {
        foo: "hello" //Should give typeScript warning - bar doesn't exist.
    }
};

Upvotes: 1

Related Questions