user4676340
user4676340

Reputation:

Declare a variable, having a key being a concatenation of two types

I would like to lock the creation of an object by declaring that the keys in it are the concatenation of two types. Since it's blurry, let me picture it with some code :

type Letter = 'A' | 'B' | 'C';

boxes: { [ID in Letter]: string }[] = ...;

Right now, this code allows one to create a set of boxes like this :

boxes = [{ A: 1 }]; // Correct
boxes = [{ D: 1 }]; // Incorrect

What I would like to achieve is do the same thing, but incorporate digits in the keys. Something like this :

type Letter = 'A' | 'B' | 'C';
type Digit = '0' | '1' | '2';

boxes: { [ID in (Letter + '-' + Digit)]: string }[] = ...;

Where a user could then create this

boxes = { 'A-1': 1 };

Is it possible, and if so, how ?

PS : the keys have to be dynamic, i.e. I can't declare a new type made of all possible combinations

Upvotes: 3

Views: 84

Answers (2)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249476

No this is not possible, there is no support for manipulation of string literals.

If your set of strings is limited (as in the provided example) then your best bet is to generate all the combinations (should not be that many and you could write a script to generate them)

If you have a lot of possible combinations, then you might do better with just a simple index signature.

Another approach is to redefine your data structure in a way where the second part of the index is actually a nested object, it's more verbose, but typesafe:

type Letter = 'A' | 'B' | 'C';
type Digit = '0' | '1' | '2';

type UnionOfJustOneProperty<T extends string, TAll extends string> = T extends string ? { [P in T]: string } & { [P in Exclude<TAll, T>]?: never }: never;
let boxes: { [P in Letter]: UnionOfJustOneProperty<Digit,Digit> }[] = [
    { 
        A: { "0": "value"},
        B: { "1": "value"},
        C: { "0": "value", /* "1": "" */} // the commented code causes an error, we can only have one key in the object
    }
];

Upvotes: 1

Estus Flask
Estus Flask

Reputation: 222319

A-1 string requires to evaluate (Letter + '-' + Digit) at runtime. It's impossible to achieve type safety for such keys in TypeScript.

If type safety is a requirement, keys like A-1 can't be considered an appropriate way.

Upvotes: 2

Related Questions