goscamp
goscamp

Reputation: 1106

Set type of state of React Component with TypeScript

I am tryig to use TypeScript in my React project


export enum IngridientType {
  BreadBottom = "BreadBottom",
  BreadTop = "BreadTop",
  Meat = "Meat",
  Cheese = "Cheese",
  Bacon = "Bacon",
  Salad = "Salad",
  Seeds1 = "Seeds1",
  Seeds2 = "Seeds2",
}

export type IngredientsListType<R> = { [key in keyof typeof IngridientType]?: R };

type IBurgerBuilderState<T> = { ingredients: IngredientsListType<T> };

class BurgerBuilder extends Component<{}, IBurgerBuilderState<number>> {
  state = {
    ingredients: {
       [IngridientType.Bacon]: 2,
       [IngridientType.Cheese]: 2,
    },
  };

...
}

but I am getting an error

Property 'state' in type 'BurgerBuilder' is not assignable to the same property in base type 'Component<{}, IBurgerBuilderState, any>'. Type '{ ingredients: { [IngridientType.Salad]: number; [IngridientType.Cheese]: number; }; }' is not assignable to type 'Readonly>'.

I don't understand exactly what is the problem here..

Upvotes: 3

Views: 81

Answers (2)

Damian Green
Damian Green

Reputation: 7495

export enum IngridientType {
  BreadBottom = 'BreadBottom',
  BreadTop = 'BreadTop',
  Meat = 'Meat',
  Cheese = 'Cheese',
  Bacon = 'Bacon',
  Salad = 'Salad',
  Seeds1 = 'Seeds1',
  Seeds2 = 'Seeds2',
}

export type IngredientsListType<R> = Record<IngridientType, R>

type IBurgerBuilderState<T> = { ingredients: Partial<IngredientsListType<T>> }

export class BurgerBuilder extends Component<{}, IBurgerBuilderState<number>> {
  state = {
    ingredients: {
      [IngridientType.Bacon]: 2,
      [IngridientType.Cheese]: 2,
    },
  }
}

Since you are only initialising your state with a partial set you will need use Partial. Also your IngredientsListType can be simplified with Record.

Side note, Ingridient should be spelt Ingredient

https://codepen.io/drGreen/details/wvKeNyB

Upvotes: 0

kind user
kind user

Reputation: 41893

I was tweaking in the TypeScript playground with your code and came up with following approach - used your enum together with a simple generic type:

export enum IngridientType {
  BreadBottom = "BreadBottom",
  BreadTop = "BreadTop",
}

type IngridientsType<T extends string, U> = {
    [K in T]: U;
};

interface IState {
  ingredients: IngridientsType<IngridientType, number>;
}

const state: IState = {
  ingredients: {
    [IngridientType.BreadTop]: 0,
    [IngridientType.BreadBottom]: 2,
    someOtherIngredient: 'wrongType', // ts will throw errors on it
  }
}

Edit: if you'd ask me what is causing the error in your example, I'm not 100% sure. However the example above might be a little bit more friendly?

Upvotes: 1

Related Questions