How to convert datetime string to date object via mobx-state-tree properly

652 views Asked by At

there is incoming string data which is date time format,

Its mapping this object fine;

import { types } from 'mobx-state-tree'

export const UserCard = types.model('UserCard').props({
  id: types.number,
  awarded_at: types.maybeNull(types.string),
})

at path "/0/awarded_at" value "2022-01-25T21:07:30.473502+00:00" is not assignable to type: (Date | null)

but since its datetime trying this model just changed string to date;

export const UserCard = types.model('UserCard').props({
  id: types.number,
  awarded_at: types.maybeNull(types.Date),
})

then get this error in setting object;

at path "/0/awarded_at" value "2022-01-25T21:07:30.473502+00:00" is not assignable to type: (Date | null)

So how to map incoming string data to Date object

1

There are 1 answers

0
Tholle On

One common technique is to model it as a string like you have done in your first snippet, create a view that creates a Date out of it, and use that instead:

import { types } from "mobx-state-tree";

export const UserCard = types
  .model("UserCard")
  .props({
    id: types.number,
    awarded_at: types.maybeNull(types.string)
  })
  .views((self) => ({
    get awardedAtDate() {
      return new Date(self.awarded_at);
    }
  }));

const userCard = UserCard.create({
  id: 1,
  awarded_at: "2022-01-25T21:07:30.473502+00:00"
});

console.log(userCard.awardedAtDate instanceof Date, userCard.awardedAtDate);
// true, Tue Jan 25 2022 22:07:30 GMT+0100 (Central European Standard Time)

If you don't like the approach above you can create a custom type:

import { types } from "mobx-state-tree";

function validateDate(str) {
  const date = Date.parse(str);
  if (isNaN(date)) throw new Error("Invalid date");

  return new Date(date);
}

export const IsoDate = types.custom({
  name: "IsoDate",
  fromSnapshot(value) {
    return validateDate(value);
  },
  toSnapshot(value) {
    return value.toISOString();
  },
  isTargetType(maybeDate) {
    return maybeDate instanceof Date;
  },
  getValidationMessage(snapshot) {
    // If we don't throw an error here when the snapshot is faulty (e.g. null),
    // things like types.maybeNull(IsoDate) will not work properly
    try {
      validateDate(snapshot);
      return "";
    } catch (error) {
      return error.message;
    }
  }
});

export const UserCard = types.model("UserCard").props({
  id: types.number,
  awarded_at: types.maybeNull(IsoDate)
});

const userCard = UserCard.create({
  id: 1,
  awarded_at: "2022-01-25T21:07:30.473502+00:00"
});

console.log(userCard.awarded_at instanceof Date, userCard.awarded_at);
// true, Tue Jan 25 2022 22:07:30 GMT+0100 (Central European Standard Time)