1

Then there is the code:

enum all {
  a = 'a',
  b = 'b',
  c = 'c',
}


// what I want enum
enum wanted {
  c = 'c',
}

I know there are some solutions like

type wanted = Exclude<all, all.a | all.b> // type wanted = all.c

But type is different from enum, as it's not iterable!

QC CAI
  • 21
  • 4

2 Answers2

0

An enum is simply an object at runtime. For example, your enum all gets transformed to this:

var all;
(function (all) {
    all["a"] = "a";
    all["b"] = "b";
    all["c"] = "c";
})(all || (all = {}));

// Essentially equivalent to
const all = {a: 'a', b: 'b', c: 'c'}

You can therefore use all like any normal JavaScript object. There are many different ways to pick/omit certain properties:

// ES2015 Destructuring
const {a, b, ...wanted} = all

// ES2019 Object.fromEntries
const wanted = Object.fromEntries(
  Object.entries(all)
.filter(([key]) =>
  key === 'c'
 // or if you wanted to exclude instead
// !['a', 'b'].includes(key)
)
) as {c: 'c'}

If you wanted to make the last example more type-safe, you could use this helper:

const pick = <T extends Record<string, unknown>, K extends keyof T>(
  obj: T,
  keys: readonly K[]
): Pick<T, K> =>
  Object.fromEntries(
    Object.entries(obj).filter(([key]) =>
      (keys as readonly string[]).includes(key)
    )
  ) as Pick<T, K>

const wanted = pick(all, ['c'])

Or maybe this for omitting properties instead:

const omit = <T extends Record<string, unknown>, K extends keyof T>(
  obj: T,
  keys: readonly K[]
): Omit<T, K> =>
  Object.fromEntries(
    Object.entries(obj).filter(
      ([key]) => !(keys as readonly string[]).includes(key)
    )
  ) as Omit<T, K>

const wanted = omit(all, ['a', 'b'])

In TypeScript, types can have the same names as values, so if you wanted wanted to also be a type (just like if you had written out the enum), you could define a type wanted with Exclude or Pick (like in your example).

Playground link

cherryblossom
  • 9,700
  • 2
  • 24
  • 53
  • Got it, though it seems not the perfect solution, but it works! – QC CAI Jul 23 '21 at 04:10
  • @QCCAI If this answer helped you, consider [accepting in](https://stackoverflow.com/help/accepted-answer) by clicking the checkmark. That way, this question is marked as answered and indicates that this answer solved your problem. You also get 2 reputation points! See [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) for more information. – cherryblossom Jul 23 '21 at 05:50
0

I actually find a solution to merge enum

enum Mammals {
  Humans = 'Humans',
  Bats = 'Bats',
  Dolphins = 'Dolphins'
}

enum Reptiles {
  Snakes = 'Snakes',
  Alligators = 'Alligators',
  Lizards = 'Lizards'
}

export const Animals = { ...Mammals, ...Reptiles };
export type Animals = typeof Animals;

So you can import Animals act as enum.

QC CAI
  • 21
  • 4