Typescript: Get the literal value from a generic type

Viewed 5372

Is it possible to get the literal value from a type? For example:

const createRecord = <T>(type: T, data: number) => ({ type, data })
const r = createRecord<'TYPE_1'>('TYPE_1', 101)

// The type of `r` is { type: "TYPE_1"; data: number; }

But I would like to omit the first parameter and simply write:

const createRecord = <T>(data: number) => ({ type: typeof T, data })
const r = createRecord<'TYPE_1'>(101)

Of course the previous example doesn't work because typeof T is a type, not a value.

2 Answers

Your function createRecord returns an object and an object is a value, so the type property must also have a value, not only a type. What you can do instead is let TypeScript infer the type for T from the value you give. TypeScript only infers a literal type if you constrained the generic type to string (or number, etc).

You can create the function like this:

const createRecord2 = <T extends string>(type: T, data: number) => ({ type, data })

and then you do

const r2 = createRecord2('TYPE_1', 101)

r2.type // type is inferred as 'TYPE_1'

Note that I don't specify the type for T at the call, it is deduced from the given argument.

See here the difference: playground

As Daniel mentioned in the previous message, we can infer the generic types from the parameters. The problem is that the function may contain multiple generic types, and TypeScript doesn't permit to omit some of them (you can omit all, however). So here's a workaround to the problem:

const createRecord = <S, T extends string>(type: T, data: S) => ({ type, data })
const r = createRecord('TYPE_1', 101)
// type of `r` is const r: { type: "TYPE_1"; data: number; }

Note that the generic types T and S are inferred from the parameters type and data. However you can't do this:

const createRecord = <S, T extends string>(type: T, data: S) => ({ type, data })
const r = createRecord<number>('TYPE_1', 101)
// Expected 2 type arguments, but got 1.

Also note that T must to extends string in order to obtain the string literal (otherwise, type would be simply string).

Related