简体   繁体   中英

How to force read-only arrays to have a tuple type with string literals in Typescript?

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.

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']) };

Round 2: applying to an object with multiple tuple-valued properties

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM