3

I have this enum:

    enum Options {
        Option1 = "xyz",
        Option2 = "abc"
    }

I want to use the values for type checking by creating a union type of 'xyz' | 'abc'. Here is my attempt, but I get this 'const' assertion error:

const validValues = Object.values(Options);
const validKeys = validValues as const;
                  ~~~~~~~~~~~ A 'const' assertion can only be applied to references to
                              enum members, or string, number, boolean, array, or object
                              literals.

What is the proper way to do this?

Sean Bright
  • 118,630
  • 17
  • 138
  • 146
techguy2000
  • 4,861
  • 6
  • 32
  • 48
  • 1
    `Object.values(Options)` is an array whose element type is `Options.Options1 | Options.Options2`, also known as `Options`. If you want the type `Options`, you can just use it. – jcalz Dec 05 '19 at 19:29
  • i don't want to type Options. i want 'xyz' | 'abc' – techguy2000 Dec 05 '19 at 20:20
  • 1
    Are you aware that `"xyz" | "abc"` is a supertype of `Options`? Like [this](https://www.typescriptlang.org/play/#code/KYOwrgtgBA8gDgFwJYHsQGcoG8CwAoKWRVEARigF4oAiADwE8AvagGn0PmTQCZKaBDAEYBjavgC++fADMwIYVxBRpKFAAoUxNOgBcRRehZRgtOABskwpAgCqIEnrpNqUAD4CR1AJTZ2x0xZWtvZofJoGANxQAPTRUCgA1vz0hBJAA)? TypeScript doesn't give you a way to automatically widen `Options` to `"xyz" | "abc"`, but it's not clear why you need this. Maybe you could edit in a use case for your code? What specifically do you need to do with the type `"xyz" | "abc"` that you currently cannot do with `Options`? – jcalz Dec 05 '19 at 20:27
  • 1
    Possible duplicate of [getting a type for the values of a string enum](https://stackoverflow.com/questions/50884025/getting-a-type-for-the-values-of-a-string-enum) – jcalz Dec 05 '19 at 20:29
  • my ultimate goal is to create a function like this: `const myFn = (input: {[key in keyof typeof Options]: string}) => {}`; right now, it's allowing only `Option1` and `Option2` as the key, i want to it to allow only `xyz` and `abc` – techguy2000 Dec 05 '19 at 20:29
  • 1
    Note that suggestion here has been "use `Options` as your type". If [I do that](https://www.typescriptlang.org/play/#code/KYOwrgtgBA8gDgFwJYHsQGcoG8CwAoKWRVEARigF4oAiADwE8AvagGn0PmTQCZKaBDAEYBjavgC++fADMwIYVxBRpKFAAoUxNOgBcRRehZRgtOABskwpAgCqIEnrpNqUAD4CR1AJTZ2x0xZWtvZofJoGANxQAPTRUCgA1vz0hBJSeMLaCFAQ9ABiSlRqSCBwYAh6WFAA2gnAKSX6JOgAunroCABOJQDmUOI+FAB82P3puQVqVULCjqxQDIxz-V5RsfFJ9PgTIFNQM8sDa3HAnZ0onUYQSOjovQtM2-m7VQAmwNJzRouHq4Trp3Olyg72kUDkJjgwAUwFeQA) (using `[K in Options]` instead of `[K in keyof typeof Options]`) it looks good to me. What specifically is the problem? – jcalz Dec 05 '19 at 20:34
  • This is getting very close. Is there a way to make `myFn({ abc: "" });` and `myFn({ xyz: "" });`. valid? Also, there is one more complication, let's say the enum value is proper case like `Xyz` and I want to limit on lower cases alway `xyz`, how could I do that with just the Options type? – techguy2000 Dec 05 '19 at 20:42
  • `const myFn = (input: Partial<{ [K in Options]: string }> ) => { }` will accept `myFn({ abc: "" })` (but it will also accept `myFn({})`) – Klas Mellbourn Dec 05 '19 at 20:43
  • ah, very nice. now how do I have the lower case conversion issue? – techguy2000 Dec 05 '19 at 20:45
  • I don't think you can make case insensitive types https://stackoverflow.com/questions/43677527/typescript-type-ignore-case – Klas Mellbourn Dec 05 '19 at 20:48
  • i was thinking i could get ['Xyz', 'Abc'] array from the enum first, then map it to lower case array ['xyz', 'abc'], then do ['xyz', 'abc'] as const, then i can convert it to 'xyz' | 'abc' union type... – techguy2000 Dec 05 '19 at 20:54

1 Answers1

1

You can use the Options enum as a type

enum Options {
        Option1 = "xyz",
        Option2 = "abc"
 }

let validValue: Options
validValue = Options.Option1

console.log(validValue) // xyz

// however, note that this is not allowed
// validValue = 'xyz'

This is another variation, not actually using enums

type Options2 = {
    Option1: 'xyz',
    Option2: 'abc'
}

type keys = keyof Options2 // 'Option1' or 'Option2'
type values = Options2[keys] // 'xyz' or 'abc'

let validValue2: values
validValue2 = 'xyz'
console.log(validValue2) // xyz (duh!)

// this is not allowed
// validValue2 = 'nope'
Klas Mellbourn
  • 42,571
  • 24
  • 140
  • 158
  • i am restricted to use enum. the code doesn't compile in vscode. i get `'Options' refers to a value, but is being used as a type here`. and i don't see how this will check for 'xyz' and 'abc'. also, you are manually using Options.Option1 here, i was looking for way to dynamically create the union type regardless of the name of the enum key... – techguy2000 Dec 05 '19 at 20:18
  • @techguy2000 the code compiles fine on my machine and on http://www.typescriptlang.org/play. `validValue` can only be assigned one of the enum values (`Options.Option1` or `Options.Option2`), so the compiler essentially checks for it to be either `xyz` or `abc`, no other values are possible. – Klas Mellbourn Dec 05 '19 at 20:23
  • my bad. i was const Options = MyOriginalEnum for the original post – techguy2000 Dec 05 '19 at 20:50