I'm not sure how to best explain my problem…
I have this function that uses type inference to infer a union type from an array of strings:
enumerated({
keywords: [ "", "one", "two", "three" ],
}) // ← returns a `ParseEnum<"" | "one" | "two" | "three">` using inference, works OK!
The options object can also take an aliases object whose keys must not be in the keywords, and values must be in the keywords.
enumerated({
keywords: [ "", "one", "two", "three" ],
aliases: { "empty": "", "un": "one" }, // ← valid, "" and "one" are valid keywords, and none of "empty" or "un" are keywords
}) // ← returns a `ParseEnum<"" | "one" | "two" | "three">` using inference, works OK!
enumerated({
keywords: [ "", "one", "two", "three" ],
aliases: { "un": "on" }, // ← invalid: "on" is not a keyword (here, detects a typo)
}) // ← returns a `ParseEnum<"" | "one" | "two" | "three">` using inference, works OK!
enumerated({
keywords: [ "", "one", "two", "three" ],
aliases: { "one": "" }, // ← invalid, "one" is a member of keywords
}) // ← returns a `ParseEnum<"" | "one" | "two" | "three">` using inference, works OK!
I can get the first two to work, but not the third.
I tried something like the following, which works for values, but not keys (Aliases is always inferred to string, and Exclude<> has no effect):
export function enumerated<Keywords extends string, Aliases extends string>(
options: {
keywords: Keywords[];
aliases?: Record<Exclude<Aliases, Keywords>, NoInfer<Keywords>>;
},
): ParseEnum<Keywords>;
I also tried variations putting the Exclude<> in the Aliases definition or using an index signature with remapping using Exclude<>.
And whereas I need to reference the Keywords type in the return type, Aliases is there only for type checking of the keys.
Now I would understand if this is not possible at all; all of this will be checked at runtime anyway, I'd just want to get a type checking error if possible.