-1

I'd like to convert some JS arrays into TypeScript enums.

I know I can do:

export enum FRUIT {
  PEACH,
  BANANA
}

But in this case 'FRUITS' is exported from a separate file, and has the format:

const FRUIT = {
  PEACH: "delicious peach",
  BANANA: "wow a banana that's awesome",
  PEAR: "gross pear do not allow pear using the Enum"
};

(I want to ensure only a subset of fruits, eg "delicious peach" can be set for ACCEPTABLE_FRUIT )

I need to do:

export enum ACCEPTABLE_FRUIT {
  FRUITS.PEACH,
  FRUITS.BANANA
}

However this is a syntax error:

Only numeric enums can have computed members, but this expression has type 'string'. If you do not need exhaustiveness checks, consider using an object literal instead.

How can I use a property key (object.key) in a TypeScript Enum? Alternatively, if I can't, how can I get around the syntax error?

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • 1
    What _is_ `FRUITS`? You seem to be trying to use the _values_ from it as _names_, which doesn't make much sense - do you want e.g. `export enum FRUIT_TYPES { PEACH = FRUIT.PEACH, ... }`? Or maybe something where you can only use e.g. `keyof typeof FRUITS` (like `"PEACH"`) as a value? How would you use this once you've created it? – jonrsharpe May 07 '21 at 12:45
  • 1
    Please [edit] the question to include this information. – jonrsharpe May 07 '21 at 12:51
  • And is that set of strings `keyof typeof FRUIT`? Please put this in the question, along with an example showing how you intend to _use_ it. – jonrsharpe May 07 '21 at 12:52
  • It sounds like you want a `valueof` equivalent, see e.g. https://stackoverflow.com/a/49286056/3001761, an enum isn't the right direction. – jonrsharpe May 07 '21 at 12:53
  • 1
    Try it in the playground - `type FRUIT_NAMES = keyof typeof FRUIT` would be `"PEACH" | "BANANA" | "PEAR"`. – jonrsharpe May 07 '21 at 12:54
  • [Try it in the playground](https://www.typescriptlang.org/play?#code/MYewdgzgLgBAYgJQKoEkAqMC8MDeAoGGABQFEBBAYQAkAuGAIgBMBTAGwEth2QBXCGAA7MAhsAAW9ADR4AvgG48eKAE8h8ZOgD6AOTIBZEgGUsMANbNlIAGYwVQ6+tRoFQA) – jonrsharpe May 07 '21 at 12:57
  • [Edit] the question. Please provide the actual context, this seems to be an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) - for example, if you're asking about a subset, having an example with only one member isn't helpful. – jonrsharpe May 07 '21 at 12:58
  • 1
    Then yes, you probably want a "valueof" with either `Pick` ("only peach or banana") or `Omit` ("not pear") - see https://www.typescriptlang.org/docs/handbook/utility-types.html. That's not going to get you to an enum, though. – jonrsharpe May 07 '21 at 13:07

1 Answers1

2

This doesn't get you an enum, but if your goal is just to be able to able to express "either FRUIT.PEACH or FRUIT.BANANA" you don't need one.

  • First, you need the values of FRUIT to be typed more specifically than string, which you can do with as const (see literal inference):

    const FRUIT = {
      PEACH: "delicious peach",
      BANANA: "wow a banana that's awesome",
      PEAR: "gross pear do not allow pear using the Enum"
    } as const;
    
  • Second, you want a "valueof" type as shown in jcalz's answer to Is there a `valueof` similar to `keyof` in TypeScript?:

    type ValueOf<T> = T[keyof T];
    
  • Finally you can use the Pick or Omit utility types to select the props from typeof FRUIT you want to include:

    type ACCEPTABLE_FRUIT = ValueOf<Pick<typeof FRUIT, "PEACH" | "BANANA">>;
    // type ACCEPTABLE_FRUIT = "delicious peach" | "wow a banana that's awesome";
    

Playground

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Just wanted to acknowledge you were right earlier when you said this was an y/x problem. I thought enums were the only way to restrict values in this situation but obviously not. – mikemaccana May 08 '21 at 14:55