Dynamisk løse egenskapstype basert på en annen egenskapsverdi i TypeScript
Jeg har følgende TypeScript-grensesnitt:
interface SelectProps {
options: Option[];
value: string[];
onChange: (value: string[]) => void;
}
Jeg vil legge til en boolean kalt isMultiple som vil endre typene til de andre egenskapene.
Når isMultiple=true
- håndhev
value:string[] - håndhev
onChange: (value: string[]) => void;
Når isMultiple=false
- håndhev
value:string - håndhev
onChange: (value: string) => void;
Er det mulig å dynamisk sette typen til andre egenskaper basert på verdien til én egenskap?
Svar #1
Det er litt sent, men jeg håper det hjelper andre slik det hjalp meg.
Diskriminerte unioner, også kjent som taggede unioner eller algebraiske datatyper, kan brukes til å løse dette problemet.
interface MultipleSelectProps {
isMultiple: true;
options: string[];
value: string[];
onChange: (value: string[]) => void;
}
interface SingleSelectProps {
isMultiple: false;
options: string[];
value: string;
onChange: (value: string) => void;
}
type SelectProps = MultipleSelectProps | SingleSelectProps;
Brukseksempel:
function Select(props: SelectProps) {
if (props.isMultiple) {
const { value, onChange } = props;
onChange(value);
} else if (props.isMultiple === false) {
const { value, onChange } = props;
onChange(value);
}
}
Merk: Når
isMultipleerundefinedellernull, er det ikke mulig å utlede den spesifikke typen avSelectProps. I disse tilfellene er det nødvendig å gjøre en streng sammenligningisMultiple === false.
Kilde: https://blog.mariusschulz.com/2016/11/03/typescript-2-0-tagged-union-types
Svar #2
OPPDATERING :
Faktisk kan det gjøres enklere. Alt som kreves her, er å bruke en unionstype som dette:
type SelectProps = {
isMultiple: true;
options: string[];
value: string[];
onChange: (value: string[]) => void;
} | {
isMultiple: false;
options: string[];
value: string;
onChange: (value: string) => void;
}
Du kan gjøre bruk av TypeScripts distributive betingede typer.
Så typen din vil se slik ut:
type SelectProps<TMultiple = boolean> = TMultiple extends true
? {
isMultiple: TMultiple;
options: string[];
value: string[];
onChange: (value: string[]) => void;
}
: {
isMultiple: TMultiple;
options: string[];
value: string;
onChange: (value: string) => void;
};
Her er et raskt eksempel.
