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"
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.