Reputation: 913
I have a configuration object as follows:
const config = { envs: ['dev', 'test', 'prod'], targets: ['> 2%'] };
Currently, the typescript compiler infers the type of this object to be:
type IConfig = { envs: string[], targets: string[] };
Which makes sense as I might mutate this array at some point after declaration.
I'm not going to change it though, so I'd like it to be:
type IConfig = { envs: ['dev', 'test', 'prod'], targets: ['> 2%'] };
Is there any way to tell the compiler to infer the type of config.envs
as a tuple type with string literals (without typing it out)?
Edit: The best answer is 90% of the way there, but I'm hoping for a method that can be applied to the object as a whole rather than each of the properties. I've added another property to the examples to make this clearer.
Upvotes: 1
Views: 948
Reputation: 30929
Combining the standard trick to infer literal types with a trick I just learned to infer a tuple type rather than an array type:
function asTupleOfLiterals<T extends string, U extends [T, ...T[]]>(tuple: U): U {
return tuple;
}
const config = { envs: asTupleOfLiterals(['dev', 'test', 'prod']) };
Miraculously, if we just wrap [T, ...T[]]
in an object with an index signature, the contextual typing seems to work:
function asObjectOfTuplesOfLiterals<T extends string,
U extends {[n: string]: [T, ...T[]]}>(obj: U): U { return obj; }
const config = asObjectOfTuplesOfLiterals(
{ envs: ['dev', 'test', 'prod'], targets: ['> 2%'] });
FTR, there's an open suggestion to make it easier to infer literal types and one to make it easier to infer tuple types.
Upvotes: 2