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"},
};
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: