Home > Mobile >  Controled prop name in TypeScript
Controled prop name in TypeScript

Time:12-22

I'm stuck with a TypeScript typing problem and can't find anything related.

I'm trying to add dynamic slots to my components, and want props' name to be a specific template including any string, a number and the 'Slot' string (i.e. custom3Slot).

What I'd like to achieve is to declare this type of props like this in my component's props TS declaration:

[key: SlotName]: ReactElement; 

For now, SlotName is declared like this :

type SlotName = `${string}${number}Slot`;

The problem is the first string can only take one character. So "c3Slot" is valid, but "cu3Slot" or "custom3Slot" are not. I can't find a way to make this first string being of any length.

Complete exmaple (playground link):

type SlotName = `${string}${number}Slot`;

interface TheInterface {
    [key: SlotName]: ReactElement; 
}

const x: TheInterface = {
    c3Slot:  /*...*/,
    cu3Slot: /*...*/, // Error: Object literal may only specify known
                      // properties, and 'cu3Slot' does not exist in type
                      // 'TheInterface'. (2322)
};

CodePudding user response:

Surprisingly, ${string}${number} just means "a single character followed by a number" even though ${string} on its own (without another placeholder after it) would allow multiple characters. There's a feature suggestion to...update...that behavior (originally a bug report), but it was marked "working as intended" by the language creator and closed.

Until/unless they do that, you can define SlotName as a union of a bunch of patterns to allow multiple characters:

type SlotName = 
    `${string}${number}Slot` |
    `${string}${string}${number}Slot` |
    `${string}${string}${string}${number}Slot` |
    `${string}${string}${string}${string}${number}Slot` |
    `${string}${string}${string}${string}${string}${number}Slot` |
    `${string}${string}${string}${string}${string}${string}${number}Slot` |
    `${string}${string}${string}${string}${string}${string}${string}${number}Slot` |
    `${string}${string}${string}${string}${string}${string}${string}${string}${number}Slot`;

That allows:

const x: TheInterface = {
    c3Slot: {type: "a"},
    cu3Slot: {type: "b"},
    cxx3Slot: {type: "c"},
    cxxx3Slot: {type: "d"},
    cxxxx3Slot: {type: "e"},
    cxxxxx3Slot: {type: "f"},
    cxxxxxx3Slot: {type: "g"},
    cxxxxxxx3Slot: {type: "h"},
};

Playground link

Not ideal, but it works. Keep going for as many characters as you need.

(Perhaps someone better at TypeScript than I am can point out how to use a recursive or mapped type for it.)

CodePudding user response:

  • Related