publicJorn
publicJorn

Reputation: 2494

How to populate mobx-state-tree map from existing object

This is a simplified version of my Store. I want to initialise it with data coming from json.

However, typescript keeps bothering me with errors.

const DistrictModel = types.model('District', {
  id: types.string,
  name: types.string,
  borders: types.array(types.string),
  owner: 0,
})

interface IDistrictModel extends Instance<typeof DistrictModel> {}

const Store = types.model({
  mapId: types.string,
  districts: types.map(DistrictModel),
})

interface IStore extends Instance<typeof Store> {}


// Imported from mapdata.json

const mapData = {
  "id": "testmap",
  "districts": {
    "topleft": { "name": "topleft", "borders": ["topright", "bottomleft"] },
    "topright": { "name": "topright", "borders": ["bottomright", "topleft"] },
  }
}

const createStore = (): IStore => {
  const store = Store.create({
    mapId: mapData.id,
    // Also tried with <string, IDistrictModel> to make it more readable
    districts: new Map(
      Object.entries(mapData.districts).map(([id, district]) => [
        id,
        DistrictModel.create({ id, ...district }),
      ]),
    ),
  })

  return store
}

Typescript says:

Type 'Map<string, { id: string; name: string; borders: IMSTArray<ISimpleType<string>> & IStateTreeNode<IArrayType<ISimpleType<string>>>; owner: number; } & NonEmptyObject & IStateTreeNode<...>>' is not assignable to type 'IKeyValueMap<ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; name: ISimpleType<string>; borders: IArrayType<ISimpleType<string>>; owner: IType<number | undefined, number, number>; }>>>'.

Index signature is missing in type 'Map<string, { id: string; name: string; borders: IMSTArray<ISimpleType<string>> & IStateTreeNode<IArrayType<ISimpleType<string>>>; owner: number; } & NonEmptyObject & IStateTreeNode<...>>'.

I find it very hard to read this kind of typescript errors, so I have trouble figuring out what is wrong.
I have tried making it more readable with new Map<string, IDistrictModel>. This results in:

Type 'Map<string, IDistrictModel>' is not assignable to type 'IKeyValueMap<ModelCreationType<ExtractCFromProps<{ id: ISimpleType<string>; name: ISimpleType<string>; borders: IArrayType<ISimpleType<string>>; owner: IType<number | undefined, number, number>; }>>>'.

Index signature is missing in type 'Map<string, IDistrictModel>'.

It seems an MST map can't be initialised with an actual new Map.

Can anyone help out?

EDIT

Example sandbox: https://codesandbox.io/s/mst-typescript-ji8ol?file=/src/index.ts

Upvotes: 3

Views: 3531

Answers (1)

publicJorn
publicJorn

Reputation: 2494

@Tholle's comment made me realise that even even though districts in MST is declared as a Map you can't "fill" it with new Map().
One actually needs to pass in an object literal to feed an MST map in the create function.

It's not very functional (at all...), but with the below code I did get it to work.

const createStore = (): IStore => {
  const districts: { [k: string]: any } = {}

  for (const [key, district] of Object.entries(mapData.districts)) {
    districts[key] = { id: key, ...district }
  }

  return GameStore.create({
    mapId: mapData.id,
    districts,
  })
}

Upvotes: 2

Related Questions