Webman
Webman

Reputation: 1554

Create Type using object's value

Whit an object like this

const USER_EVENT = {
    pageview: 'Visit',
    order: 'Order'
}

if I would to get a type with union of all keys

type UserEventKey = 'pageview' | 'order'

I could do this

type UserEventKey = keyof typeof USER_EVENT

...but is it possible to get this type with union of all values?

type UserEventName = 'Visit' | 'Order'


type UserEventName = ???? is it possibile?

Upvotes: 6

Views: 3760

Answers (2)

jcalz
jcalz

Reputation: 330376

You can't use your USER_EVENT object as written. The compiler uses some heuristics to infer the types of variables that are not annotated. Generally speaking, the compiler sees string property values as being of type string:

const OOPS_USER_EVENT = {
    pageview: 'Visit',
    order: 'Order'
}
/* const OOPS_USER_EVENT: {
    pageview: string;
    order: string;
} */

So the compiler has forgotten about the specific "Visit" and "Order" values, and nothing you do with typeof USER_EVENT will bring them back.

Instead you need to define USER_EVENT differently. The easiest way to do that is to use a const assertion to hint that your object won't change at all, and to ask the compiler to infer the most specific type it can:

const USER_EVENT = {
    pageview: 'Visit',
    order: 'Order'
} as const;
/* const USER_EVENT: {
    readonly pageview: "Visit";
    readonly order: "Order";
} */

Now USER_EVENT has properties of the string literal types "Visit" and "Order"; the information you care about is still there.


At this point you need to take an object type like T and get the union of property value types instead of the keys. See this question for a more canonial version of this question and its answer.

You can use indexed access types of the form T[K] to get the property value types at keys of type K. If you want all keys, then T[keyof T] works:

type ValueOf<T> = T[keyof T];


type UserEventName = ValueOf<typeof USER_EVENT>;
// type UserEventName = "Visit" | "Order"

Playground link to code

Upvotes: 10

Alex Wayne
Alex Wayne

Reputation: 187272

Just index the type by it's own keys to get a union of the values.

const USER_EVENT = {
    pageview: 'Visit',
    order: 'Order'
} as const

type UserEventName = typeof USER_EVENT[keyof typeof USER_EVENT] // "Visit" | "Order"

Note the as const there. This is required to force the type to be inferred as specific strings, and not just string.

Playground

Upvotes: 6

Related Questions