Typescript gör en egenskap valfri baserat på värdet av en annan egenskap


Jag är ny på Typescript och jag kunde inte hitta några lösningar för scenariot nedan. Alla förslag skulle vara mycket hjälpsamma.

Jag skulle vilja göra egenskapen options valfri om type är SHORT_TEXT eller LONG_TEXT.

export interface Question {
  [keyName: string]: any;
  type: QuestionType;
  id: string;
  label: string;
  helpText?: string;
  placeholder?: string;
  value?: string;
  options?: Option[];
  validations?: any;
  required?: boolean;
  priority?: number;
  intent?: Intent[];
}

export type QuestionType =
  | "DROPDOWN"
  | "CHECKBOX"
  | "RADIO"
  | "SHORT_TEXT"
  | "LONG_TEXT";

export interface Option {
  id: string;
  label: string;
  value?: string;
}

Svar #1

Jag tror att det du letar efter är en "Discriminated Union". I princip som du beskrev det: värdet av en viss egenskap kan användas för att begränsa typen i en union, och i det här fallet vill du ha en (eller flera) typer där options-egenskapen är obligatorisk, och en typ där den är valfri.

export type QuestionType =
  | "DROPDOWN"
  | "CHECKBOX"
  | "RADIO"
  | "SHORT_TEXT"
  | "LONG_TEXT";

export interface Option {
  id: string;
  label: string;
  value?: string;
}

export interface Intent {};

export interface BaseQuestion {
  [keyName: string]: any;
  type: QuestionType;
  id: string;
  label: string;
  helpText?: string;
  placeholder?: string;
  value?: string;
  validations?: any;
  required?: boolean;
  priority?: number;
  intent?: Intent[];
}

export interface TextQuestion extends BaseQuestion {
    type: "SHORT_TEXT" | "LONG_TEXT";
    options?: Option[];
}

export interface OptionQuestion extends BaseQuestion {
    type: "DROPDOWN" | "CHECKBOX" | "RADIO";
    options: Option[];
}

export type Question = TextQuestion | OptionQuestion;


const q: Question = {
    type: "SHORT_TEXT",
    id: "id_foo",
    label: "Test Question",
};

Du kan prova detta i Typescript-lekplatsen: du kommer att se att validatorn inte har något problem med q-objektet, även om det inte har någon options-egenskap. Men om du ändrar type-egenskapen på q till "DROPDOWN" eller något annat än "SHORT_TEXT" eller "LONG_TEXT", kommer validatorn att ge ett fel.

Du kommer också att märka att om du skriver q i den interaktiva lekplatsen, kommer ledtråden att ha det som en TextQuestion istället för en Question, eftersom typen har begränsats. Åtminstone i det här exemplet hindrar det dig faktiskt från att ändra q.type-egenskapen senare, men kom ihåg att skydd bara fungerar i block där typen av den unionen redan har begränsats. Om du till exempel loopar över en lista med frågor och tilldelar typen på nytt:

(questions as Question[]).forEach(q => {
  q.type = "DROPDOWN";
});

Typescript har inte begränsat varje objekts typ i det här fallet och kommer inte att skydda mot att du tilldelar type på nytt.

Hoppas detta hjälper! ✌️

Relaterade artiklar