The compiler will widen string literal type to string
, unless some specific conditions are met as explained in github issues and PR, or const assertion is used for literal value. Const assertions appeared in TypeScript 3.4:
const KeyToVal = {
MyKey1: 'myValue1',
MyKey2: 'myValue2',
} as const;
type Keys = keyof typeof KeyToVal;
type Values = typeof KeyToVal[Keys]; // "myValue1" | "myValue2"
Prior to 3.4, there was a workaround to get the same effect. To make the compiler infer literal types, you had to pass your object through a function with appropriately crafted generic type parameters, this one seems to do the trick for this case:
function t<V extends string, T extends {[key in string]: V}>(o: T): T {return o}
The whole purpose of this function is to capture and preserve types to enable type inference, it’s entirely useless otherwise, but with it you can have
const KeyToVal = t({
MyKey1: 'myValue1',
MyKey2: 'myValue2',
});
type Keys = keyof typeof KeyToVal;
type Values = typeof KeyToVal[Keys]; // "myValue1" | "myValue2"