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 isMultiple er undefined eller null, er det ikke mulig å utlede den spesifikke typen av SelectProps. I disse tilfellene er det nødvendig å gjøre en streng sammenligning isMultiple === 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.

Relaterte artikler