Below, I have a literal object {a:"a"}. I want to extract the value of the object as a literal "a", not its type string, so as to check if some other variables is "a" and not any other string.

However if I use mapped type I only get string, not "a".

Is there a way to get the value as a type?

const a = {a:"a"}
type trueIfLiteral<T extends string>= string extends T?false:true;

type key = keyof typeof a;
const t1 : trueIfLiteral<key> = true; // key is literal

type val = typeof a[key];
const t2 : trueIfLiteral<val> = false; // val is string

So the question is simply, how can I derive a type:

type valAsLiteral = "a"
1

There are 1 answers

1
CertainPerformance On BEST ANSWER

First, to make the object slightly less confusing, let's call it obj with properties key and val:

const obj = { key: "val" };

A problem here is that the object is typed as { key: string }. TypeScript has automatically widened the 'val' from 'val' to a string. If you want to prevent that widening, you can declare the object as const:

const obj = { key: "val" } as const;

This results in your code working, and

type val = typeof obj[key];

produces 'val' (and const t2 : trueIfLiteral<val> = false; // val is string fails, because val is no longer a generic string, but only val)

To get the value in the emitted JS, not in TS, you can do

const val = Object.values(obj)[0];

producing 'val', typed as 'val', with no type widening.