Here is a simple example of what I am looking for. I am implementing an array and I want to check if the multi prop is true, type of items should be number[]. Otherwise, set the type to number.
interface EnhancedSelectProps {
items: multi ? number[] : number;
multi?: boolean;
}
const EnhancedSelect = ({
items,
multi,
}: EnhancedSelectProps) => {}
I have tried the union type but it is not working. when I want to do something like this, it will give me a ts error.
interface EnhancedSelectProps {
items?: number[] | number;
multi?: boolean;
}
const EnhancedSelect = ({
items,
multi,
}: EnhancedSelectProps) => {
if(multi) console.log(items.length);
else console.log(items)
}
CodePudding user response:
Titian beat me to it but here is a version using generics
interface EnhancedSelectProps<T extends boolean> {
items: T extends false ? number : number[];
multi?: T;
}
function EnhancedSelect({
items,
multi,
}: EnhancedSelectProps<true> | EnhancedSelectProps<false>) {
if (multi) console.log(items.length);
else console.log(items)
}
CodePudding user response:
The simplest option is to use a discriminated union, discriminated on the multi
field:
type EnhancedSelectProps = {
items?: number[];
multi: true;
} | {
multi: false;
items?: number;
}
const EnhancedSelect = ({
items,
multi,
}: EnhancedSelectProps) => {
if(multi) console.log(items?.length);
else console.log(items)
}
EnhancedSelect({ multi: true, items: [1,2]})
EnhancedSelect({ multi: true, items: 1}) // error
EnhancedSelect({ multi: false, items: [1,2]}) // error
EnhancedSelect({ multi: false, items: 1})
EnhancedSelect({ items: [1,2]}) // error
EnhancedSelect({ items: 1 })
If you are using an older version of Typescript (<= 4.6), you can't destructure the parameter and still have TS understand the relationship between the fields, you will need to wither use the parameter itself or destructure after the check:
const EnhancedSelect = (p: EnhancedSelectProps) => {
if(p.multi) {
console.log(p.items?.length);
const { items } = p
console.log(items?.length);
} else {
console.log(p.items)
const { items } = p
console.log(items)
}
}