Here is the setup I have. The concept is to receive a generic and options shape, deduce the necessary options based on the generic and the type
key of the options shape, and appropriately restrict the options.
type OptionProp<T extends string | boolean> = {
defaultValue: T;
} & (T extends string
? { type: "select"; options: T[] } | { type: "text" }
: { type: "checkbox" });
function useFixtureOption<T extends string>(
name: string,
prop: OptionProp<T>
): T {
console.log(prop);
return prop.defaultValue;
}
useFixtureOption<"foo" | "bar">("field", {
type: "select",
options: ["foo", "bar"],
defaultValue: "foo",
});
Nevertheless, Typescript seems to be confused about my options
type, defined as T[]
, interpreting it as
"foo"[] | "bar"[]
instead of ("foo" | "bar")[]
:
https://i.sstatic.net/NQuzW.png
If I avoid using a conditional type here, everything works properly:
type OptionProp<T extends string> = {
defaultValue: T;
} & ({ type: "select"; options: T[] } | { type: "text" });
However, I want to enforce that a boolean T
requires type: checkbox
, while text/select necessitate a string T.
I think there might be some intricacy in the type system that I'm not grasping here, but I'm unsure where it lies. My assumption is that the T extends string
check is overly restrictive, leading to a type option for each member of the T union. Is this accurate, and if so, how can I resolve it?
Edit: It appears I've stumbled upon distributed conditional types. F<A|B> = F<A> | F<B>
, illustrating why I'm experiencing these issues. Now, how can I rectify them?