How to create a union type from a namespace in typescript

Viewed 837

I have something like this:

// enums.ts
export enum UserAction {
  Login,
  Logout
}

export enum PostAction {
  DeletePost,
  CreatePost
}

And in another file, I want to create a union type from all the exported items in "enums.ts"

I tryed to write code like below, but something went wrong. It works only when I join them hand by hand.

import * as types from "./enums";
import { PostAction, UserAction } from "./enums";

type MyOldUnion = PostAction | UserAction;       // works
type MyUnion = typeof types[keyof typeof types]; // not working

function useUnionType(type: MyUnion) {}
function useOldUnionType(type: MyOldUnion) {}

// TS2345: Argument of type 'PostAction.CreatePost' is not assignable to parameter of type 'MyUnion'.
useUnionType(PostAction.CreatePost); 
useOldUnionType(PostAction.CreatePost);

Is there a way to create a union type programmatically from a namespace?

Or maybe it's a bad choice to do so in typescript?

My typescript version: 3.9.7

1 Answers

Figure out one possible solution.

The key problem is how to get enum item type from a enum type.

// A simple case:

enum Enum { A, B }
type EnumType = typeof Enum;                        // typeof enum itself
type EnumItemType = typeof Enum[keyof typeof Enum]; // typeof enum items (We need!)

function test1(arg: EnumType) {}
function test2(arg: EnumItemType) {}

test1(Enum);
test2(Enum.A);

Then, get union type from a namespace export should be

// My namespace case:

import * as enums from "./enums";

type ValuesOf<E> = E[keyof E];

type Enums = typeof enums;

type MyUnion = {
    [k in keyof Enums]: ValuesOf<Enums[k]>;
}[keyof Enums];

// MyUnion => enums.PostAction | enums.UserAction
//  works
Related