TypeScript Warning and Prisma Model Parameters

Hello all - very thankful for this incredible framework! I’ve used it to build an internal app for my company over the past couple months, and the company loves it and is now putting resources into expanding it. It wouldn’t have been possible without RedwoodJS! Big fan.

I have two components to which I am passing an object that is queried/obtained by a parent cell. Rather than passing all of the various parameters that are needed (there are several). I prefer to pass the object itself. The problem I’m running into is that the GQL query used by the cell does not retrieve all of the objects - I don’t need them in the cell or any of the dependent components. But I get a TS2739 warning that some of the properties are missing on the object being passed to the component. The fields it’s complaining about are either arrays or objects. The arrays returned by Prisma may be empty - which is fine. But I don’t want to be querying additional relations/tables if unnecessary.

I can open the definition in graphql.d.ts and mark the fields as optional by adding a ‘?’ but that’s not really the point.

Is there a proper TypeScript way to do this, rather than just ignoring the warning? I don’t want to add the related objects to the cell query because they are unnecessary and I worry they’d waste bandwidth and computation power.

Definition in graphql.d.ts:

export type VideoClip = {
  __typename?: 'VideoClip';
  id: Scalars['Int'];
  path: Scalars['String'];
  eventRecord: EventRecord;
  eventRecordId: Scalars['Int'];
  dataValues: Array<Maybe<DataValue>>;
  sequence: Scalars['Int'];
  thumbnail: Scalars['String'];
  relatedNotes: Array<Maybe<RelatedNote>>;
};

Specifically the fields it complains about are dataValues, eventRecord, and relatedNotes.

The query in the cell:

export const QUERY = gql`
  query FindVideoClipQuery($id: Int!) {
    videoClip: videoClip(id: $id) {
      id
      sequence
      path
      thumbnail
      eventRecordId
    }
  }
`

The exact warning:

TS2739: Type '{ __typename?: "VideoClip"; id: number; sequence: number; path: string; thumbnail: string; dispname: string; eventRecordId: number; }' is missing the following properties from type 'VideoClip': eventRecord, dataValues, relatedNotes

And I’m trying to pass it as follows:

<VideoClipThumbnail videoClip={videoClip} />

With the component interface defined as such:

import type { VideoClip } from 'types/graphql'

interface Props {
  videoClip: VideoClip
}

export const VideoClipThumbnail = ({ videoClip }: Props) => {

Hi @st0w I’m no TypeScript expert myself, but am learning and I think there may be a few options:

SDL Interfaces

You can implement a type like a VideoClipThumbnail:

export const schema = gql`
  interface VideoClipThumbnail {
    id: String!
    sequence: Int!
    path: String!
    thumbnail: String!
    eventRecordId: Int!
  }

  type VideoClip implements VideoClipThumbnail {
    id: String!
    sequence: Int!
    path: String!
    thumbnail: String!
    eventRecordId: Int!
    relatedNotes: [String!]!
    dataValues: [String!]!
  }
`

Note: I made up the data types for your properties

And this generates:

export type VideoClip = VideoClipThumbnail & {
  __typename?: 'VideoClip'
  dataValues: Array<Scalars['String']>
  eventRecordId: Scalars['Int']
  id: Scalars['String']
  path: Scalars['String']
  relatedNotes: Array<Scalars['String']>
  sequence: Scalars['Int']
  thumbnail: Scalars['String']
}

export type VideoClipThumbnail = {
  eventRecordId: Scalars['Int']
  id: Scalars['String']
  path: Scalars['String']
  sequence: Scalars['Int']
  thumbnail: Scalars['String']
}

Thus your

interface Props {
  videoClip: VideoClip
}

could just be

interface Props {
  videoClip: VideoClipThumbnail
}

or if you change your query

export const QUERY = gql`
  query FindVideoClipQuery($id: Int!) {
    videoClipThumbnail: videoClip(id: $id) {
      id
      sequence
      path
      thumbnail
      eventRecordId
    }
  }
`

it would be


interface Props {
  videoClipThumbnail: VideoClipThumbnail
}

Make a more concise prop type

Do similar but use TS Omit

interface Props {
  videoClip: Omit<VideoClip, 'dataValues' | 'eventRecord' | 'relatedNotes">
}

Define a thumbnail prop type



interface VideoClipThumbNail {
  eventRecordId: number
  id: string
  path: string
  sequence: string
  thumbnail: string
}

interface Props {
  videoClip: VideoClipThumbNail
}

const VideoClipThumbNail = ({ videoClip }: Props) => {

But at that point, seems to pass in the VideoClipThumbNail makes sense.

Thoughts?

Those are some ideas I had.

The Redwood team does some have ideas to rework the codeine based on @sdl-codegen/node - npm to make the types less complicated.

This may happen in v6.

Let me know how it goes! Am digging to more GraphQL codegen recently to always learning and want to improve it,

2 Likes

Thanks so much for all of this! I will experiment a bit and update. I’m inclined toward the TS Omit, as it seems the easiest if we’re only doing that in one place. But if certain instances are useful in additional areas, the SDL interface seems like the most re-usable.

This is my first big TS project - I’ve been a longtime backend coder/security engineer, and have done a bunch of freelance web stuff over the years, but really a ton of Python in my history. And of course, TS is kind of the fundamental opposite of Python. :slight_smile: But I’ve been really liking the benefits of TS, like the tremendous ease of debugging and hints.

^^ this gets me very excited @st0w It would be a pleasure to learn more if you have time to send me a DM. No pressure.

And well done!

Makes sense.

You may also consider Pick<VideoClip, 'id' | 'sequence' | 'path' | 'thumbnail' | 'eventRecordId'> as that way if more propertis/fields are added to VideoClip, it won’t be as brittle. It’s the inverse of Omit.

I try to think of SDL, and types and my queries and props as “just shapes of data” that I need to keep either the same or compatible so they can be passed around. Once you the the shape in shape, things just work nicely. And they warn you when the shapes diverge – which is really helpful (even if it feels annoying at first).

1 Like