I'm trying to define a type for an object:
const width: Rule = {
// regular keys with any name
full: "100%",
half: "50%",
// special keys
$px: [10, 50, 100],
$rem: [1, 1.5, 2],
$em: [1, 1.5, 2],
}
Where Array<number> value can only be used with special keys ('$px' | '$em' | '$rem') and string value only with regular ones.
So I tried something like this:
export type Special = "$px" | "$em" | "$rem";
export type Rule<K extends string> = {
[key: K]: K extends Special ? Array<number> : string;
}
But having an error at [key: K]:
(parameter) key: K extends string An index signature parameter type must be either 'string' or 'number'.ts(1023)
What am I doing wrong?
UPDATE:
The answer proposed in the comments doesn't work in my case, because I don't have a declared interface with known keys. I have a Record<string, string | Array<number>> instead and doing something like:
export type Rule = {
[K in keyof Record<string, any>]: K extends Special ? Array<number> : string;
};
gives an error on special keys:
(property) $px: number[] Type 'number[]' is not assignable to type 'string'.
So far I ended up with something like this:
export type Rule = Record<string, string | Array<number>> &
Partial<Record<Special, Array<number>>;
But obviously it allows to set Array<number> on regular keys which is not ideal.