reactjstypescriptnext.jsmobx

Property 'store' does not exist on type { } - MobX & React & TypeScript


I keep getting error "Property 'store' does not exist on type '{}'." from TypeScript when using Next.js with Mobx. I'm using Next.js v14.1.0 with the app router setting.

How to properly define the type for state store in Next.js?

Additional description of my code, currently my ObservableClickStore is inside the same page (page.tsx) with Home component.

Home is a component that will be passed again to Games, and page.tsx will render Games (I'm not sure also with this approach, seems inefficient and redundant.

// ./src/app/page.tsx

class ObservableClickStore {
  counter: number = 0;
  openedCards: ICard[] = [];
  clickedCards: ICard[] = [];
  nonShuffledCharacters: ICard[] = [
    { text: "Saya", answer: "I", isRevealed: false },
    // clickCard function logic. Removed to make concise...
  ]

  characters = this.nonShuffledCharacters.sort(() => Math.random() - 0.5);
  constructor() {
    makeObservable(this, {
      counter: observable,
      characters: observable,
      clickCard: action,
      toggleIsRevealed: action,
      clearClickedCards: action,
      reset: action,
    });
    autorun(() => console.log(this.report));
  }

  get report() {
    return this.characters;
  }

  toggleIsRevealed = (card: ICard) => {
    const index = this.characters.indexOf(card)
    this.characters[index].isRevealed = !this.characters[index].isRevealed;
  }

  clearClickedCards = () => {
    this.clickedCards = []
  }

  reset = () => {
    // reset function logic. Removed to make concise...
  }

  clickCard = (card: ICard) => {
    // clickCard function logic. Removed to make concise...
  }
}

const observableClickStore = new ObservableClickStore();

const Home = observer(({ store }) => {

  const backside = "🍊";
  const quizCardList = store.characters.map((character: ICard, i: number) =>
    <div className='m-1' key={i}>
      <div onClick={() => store.clickCard(character)}>
        <QuizCard revealCard={character.isRevealed} backside={backside} frontside={character.text} />
      </div>
    </div >
  )

  return (
    <>
      // render HTML...
    <>
})

const Games = () => {
  return <Home store={observableClickStore} />
}

export default Games;

Solution

  • You can tell the observer which type of store it's passing to your page like so:

    const observableClickStore = new ObservableClickStore();
    
    const Home = observer<{ store: ObservableClickStore }>(({ store }) => {
      // ...
      return <></>;
    });
    
    const Games = () => {
      return <Home store={observableClickStore} />;
    };
    
    export default Games;