0

I have this list of dishes:

const dishes = [
    {
      id: 'dish01',
      title: 'SALMON CRUNCH',
      price: 99,
      ingredients: [
        'SALMON',
        'CRUNCH SALAD',
      ],
      options: [
        {
          option: 'BASE',
          choices: ['RICE', 'SPAGHETTI', 'MIX'],
          defaultOption: 'MIX',
        },
      ],
    },
    {
      id: 'dish02',
      title: 'GOCHUJANG CHICKEN',
      price: 110,
      ingredients: [
        'GOCHUJANG',
        'CHICKEN',
      ],
      options: [
        {
          option: 'BASE',
          choices: ['RICE', 'SPAGHETTI', 'MIX'],
          defaultOption: 'MIX',
        },
        {
          option: 'TOPPING',
          choices: ['MAYO', 'KETCHUP', 'NONE'],
          defaultOption: 'NONE',
        },
      ],
    },
...
]

I then decide to use a useReducer (React) to keep track and build a single dish order object that goes into the card.

Is it then possible define a custom interface for each dish?

// types for dish01
type Ingredients = 'SALMON' | 'CRUNCH SALAD'

interface DishOrder {
  id: string
  withoutIngredients: Ingredients[]
  BASE: 'RICE' | 'SPAGHETTI' | 'MIX'
}

// types for dish02
type Ingredients = 'GOCHUJANG' | 'CHICKEN'

interface DishOrder {
  id: string
  withoutIngredients: Ingredients[]
  BASE: 'RICE' | 'SPAGHETTI' | 'MIX'
  TOPPINGS: 'MAYO' | 'KETCHUP' | 'NONE'
}

if not, is this then as typed as it can get:

interface DishOptions {
  [key: string]: string
}

// https://stackoverflow.com/a/45261035/618099
type DishOrder = DishOptions & {
  id: string
  withoutIngredients: string[]
}
Norfeldt
  • 8,272
  • 23
  • 96
  • 152

2 Answers2

2

Looks like a perfect case for generics?

type Ingredients = 'SALMON' | 'CRUNCH SALAD'

interface DishOrder<T> {
  id: string
  withoutIngredients: T[]
  BASE: 'RICE' | 'SPAGHETTI' | 'MIX'
  TOPPINGS: 'MAYO' | 'KETCHUP' | 'NONE'
}

// const yourDishOrder: DishOrder<Ingredients> = ...
DedaDev
  • 4,441
  • 2
  • 21
  • 28
1

I would do it like this:

enum Ingredient {
  Salmon = "Salmon",
  CrunchSalad = "Crunch Salad",
  ...
}

enum Base {
  Ris = "Ris",
  ...
}

enum Topping {
  Mayo = "Mayo",
  ...
}

interface DishOrder {
  id: string;
  withoutIngredients: Ingredient[];
  toppings?: Topping[];
  base: Base[];
}

this is not an extreme case at all.

Łukasz Karczewski
  • 1,084
  • 8
  • 12
  • Thank you for this very quick reply and suggestion. It looks interesting and like a better approach than the last resort I suggested. Do the types have to be 'typed' or can I code something that declares the types? – Norfeldt Apr 20 '21 at 11:33
  • It might not be an extreme case :D but I quickly go to the deeper end of pool instead of just staying longer in the "kiddie" pool. – Norfeldt Apr 20 '21 at 11:36
  • I'm afraid they have to be typed. Unless you have an array of options somewhere – Łukasz Karczewski Apr 20 '21 at 11:38
  • If I did then how would I then do it? – Norfeldt Apr 20 '21 at 11:43
  • I think in such a case enums would not make much sense. I would suggest doing something like this: ``` const ingredientsOptionsArray = [...] as const; export type Ingredient = (typeof ingredientsOptionsArray)[number] ``` here's a similar example: https://www.typescriptlang.org/play?#code/MYewdgzgLgBAhjAvDA2gIjmgNDNAjbXYNAXXghlEigCgoBPABwFMYBBJGACgZZADN4AShRgArgFs8zAE4kgA – Łukasz Karczewski Apr 20 '21 at 11:50
  • Getting into the deeper end ;-) - thank you! Will give it a look. Thinking that I can construct the array from my `const dishes` array – Norfeldt Apr 20 '21 at 11:53
  • Newbie question: what why is it `[number]` and not just `[]` ? – Norfeldt Apr 20 '21 at 11:57
  • Because you want to get the type of the result of getting the value of a numeric key. `(typeof ingretientsOptionsArray)[]` would mean an array of arrays of ingredient strings – Łukasz Karczewski Apr 20 '21 at 12:17