miragejs icon indicating copy to clipboard operation
miragejs copied to clipboard

How to properly type models?

Open rfmiotto opened this issue 4 years ago • 8 comments

Dear,

I am trying to mock a server with MirageJS using Typescript, but I am not sure how to properly type the models and, unfortunately, Mirage docs does not say how to go about this.

To exemplify the problem, let's assume the following problem with relationships: say we have a given customer who can schedule an appointment at a given business. I tried to create the Models using the code below:

type Appointment = {
  date: string;
  status: string;
  business: Business;
  customer: Customer;
};

type Customer = {
  name: string;
  email: string;
  phone: string;
  appointments: Appointment[];
};

type Business = {
  name: string;
  image: string;
  appointments: Appointment[];
  customers: Customer[];
};

export function makeServer() {
  const server = createServer({
    models: {
      appointment: Model.extend<Partial<Appointment>>({
        customer: belongsTo(), // error here
        business: belongsTo(), // error here
      }),
      customer: Model.extend<Partial<Customer>>({
        apointments: hasMany("appointment"), // error here
      }),
      business: Model.extend<Partial<Business>>({
        customers: hasMany("customer"), // error here
        appointments: hasMany("appointment"), // error here
      }),
    },
    // ...

but then, I get some errors saying (all errors are the same, so I will show here only the first one):

The expected type comes from property 'customer' which is declared here on type 'Partial<Appointment>'

If I change the type of the relations to any, then the error disappears. For example:

type Appointment = {
  date: string;
  status: string;
  // business: Business;
  // customer: Customer;
  business: any; 
  customer: any;
};

But I'm not sure if that is the proper way to do so.

Does anyone know what I'm doing wrong? I believe Mirage docs would benefit from a more detailed explanation about typing Models.

Thank you!

rfmiotto avatar Mar 17 '22 12:03 rfmiotto

Hi there, have you tried typing your models as Model.extend<Appointment>, without the Partial<>? You'll need to provide default values for any static properties.

Also, I find that I need to type my server config (the object passed to createServer() thus:

const serverConfig: ServerConfig<typeof models, typeof factories> = {

Where my models and factories have been defined and typed elsewhere, and ServerConfig is imported like:

import type { ServerConfig } from 'miragejs/server';

Typescript support was not baked into mirage from the start, and it's not 100% perfect, but I find that I'm usually able to accomplish what I need, aside from some more complex cases like traits.

IanVS avatar Mar 17 '22 12:03 IanVS

Hi @IanVS,

Thank you very much for your quick reply. So apparently I need to change the way I'm creating the server. Would you have a sample public project in your GitHub (maybe you know about one) showing how to implement this? That would be super helpful.

Thank you once again! All the best

rfmiotto avatar Mar 17 '22 13:03 rfmiotto

I'm sorry, I don't have anything open-source that I can share. And honestly, I don't have models that relate to each other in that way (everything refers only to other ids). I'd encourage you to explore creating models and factories with the correct types, and then typing the config object as I suggested above. And if you get stuck, feel free to reply here, or hop into ember's discord in the #ec-mirage channel.

IanVS avatar Mar 17 '22 13:03 IanVS

Hi @IanVS,

Thank you very much for your quick reply. So apparently I need to change the way I'm creating the server. Would you have a sample public project in your GitHub (maybe you know about one) showing how to implement this? That would be super helpful.

Thank you once again! All the best

Hi @rfmiotto did you manage to solve this issue? Would love to see a code sample if possible please! 👍

jimsheen avatar Mar 28 '22 15:03 jimsheen

Hi @jimsheen

Unfortunately no. I ended up removing the types from the models. I didn't want to spend too much time on mocking the server, so I took the easy way out.

But in case you have a solution, please let me know.

rfmiotto avatar Mar 29 '22 15:03 rfmiotto

I'm sorry, I don't have anything open-source that I can share. And honestly, I don't have models that relate to each other in that way (everything refers only to other ids). I'd encourage you to explore creating models and factories with the correct types, and then typing the config object as I suggested above. And if you get stuck, feel free to reply here, or hop into ember's discord in the #ec-mirage channel.

Hi @IanVS,

I would appreciate it if you could provide a code snippet doing what you mentioned here, I mean typing the ServerConfig for the case provided by @rfmiotto?

Thank you in advance!

tulliocba avatar Jul 26 '22 10:07 tulliocba

Hi there, have you tried typing your models as Model.extend<Appointment>, without the Partial<>? You'll need to provide default values for any static properties.

Also, I find that I need to type my server config (the object passed to createServer() thus:

const serverConfig: ServerConfig<typeof models, typeof factories> = {

Where my models and factories have been defined and typed elsewhere, and ServerConfig is imported like:

import type { ServerConfig } from 'miragejs/server';

Typescript support was not baked into mirage from the start, and it's not 100% perfect, but I find that I'm usually able to accomplish what I need, aside from some more complex cases like traits.

I get that this is a very easy workaround, but it would also be very easy to change the types for mirage such that this is not needed

GideonMax avatar Oct 29 '23 06:10 GideonMax

@GideonMax if you're willing to submit a PR, I'd be happy to review it!

IanVS avatar Oct 30 '23 11:10 IanVS