Search code examples
javascripttypescriptgraphqlcode-generationgraphql-js

TS compiler error: Type 'string' is not assignable to type 'Status'


I am defining the following Query object:

export const Query = {

  // Feed
  feed(parent, args, ctx: Context, info) {
    const { filter, skip, first, orderBy } = args
    const where = filter
      ? {
          AND: [
            { status: 'ACTIVE' },
            {
              OR: [
                { name_contains: filter },
                { description_contains: filter }
              ]
            }
          ]
        }
      : { status: 'ACTIVE' }

    return ctx.db.query.listings({ where, skip, first, orderBy }, info)
  },
  // ...
}

The TS compiler complains about the status: 'ACTIVE' part:

[ts]
Argument of type '{ where: { AND: ({ status: string; OR?: undefined; } | { OR: ({ name_contains: any; description_c...' is not assignable to parameter of type '{ where?: ListingWhereInput; orderBy?: ListingOrderByInput; skip?: number; after?: string; before...'.
  Types of property 'where' are incompatible.
    Type '{ AND: ({ status: string; OR?: undefined; } | { OR: ({ name_contains: any; description_contains?:...' is not assignable to type 'ListingWhereInput'.
      Type '{ AND: ({ status: string; OR?: undefined; } | { OR: ({ name_contains: any; description_contains?:...' is not assignable to type 'ListingWhereInput'.
        Types of property 'AND' are incompatible.
          Type '({ status: string; OR?: undefined; } | { OR: ({ name_contains: any; description_contains?: undefi...' is not assignable to type 'ListingWhereInput | ListingWhereInput[]'.
            Type '({ status: string; OR?: undefined; } | { OR: ({ name_contains: any; description_contains?: undefi...' is not assignable to type 'ListingWhereInput[]'.
              Type '{ status: string; OR?: undefined; } | { OR: ({ name_contains: any; description_contains?: undefin...' is not assignable to type 'ListingWhereInput'.
                Type '{ status: string; OR?: undefined; }' is not assignable to type 'ListingWhereInput'.
                  Types of property 'status' are incompatible.
                    Type 'string' is not assignable to type 'Status'.

Note that the Status type is auto-generated based on a enum in GraphQL SDL which looks as follows:

enum Status {
  ACTIVE
  EXPIRED
  SOLD
  DELETED
}

The generated TS definition looks as follows:

export type Status = 
  'ACTIVE' |
  'EXPIRED' |
  'SOLD' |
  'DELETED'

I don't understand why the TS compiler complains about the status: 'ACTIVE' part. According to my understanding, this is should work as status can only be either of the four defined string values?!

More info:

In case it helps, here are the generated type definitions of the other involved types (everything is generated based on GraphQL SDL):

export type Query = {
  listings: (args: { where?: ListingWhereInput, orderBy?: ListingOrderByInput, skip?: Int, after?: String, before?: String, first?: Int, last?: Int }, info?: GraphQLResolveInfo | string) => Promise<Listing[]>
  // ... other fields
}

export interface ListingWhereInput {
  AND?: ListingWhereInput[] | ListingWhereInput
  OR?: ListingWhereInput[] | ListingWhereInput
  id?: ID_Input
  id_not?: ID_Input
  id_in?: ID_Input[] | ID_Input
  id_not_in?: ID_Input[] | ID_Input
  id_lt?: ID_Input
  id_lte?: ID_Input
  id_gt?: ID_Input
  id_gte?: ID_Input
  id_contains?: ID_Input
  id_not_contains?: ID_Input
  id_starts_with?: ID_Input
  id_not_starts_with?: ID_Input
  id_ends_with?: ID_Input
  id_not_ends_with?: ID_Input
  name?: String
  name_not?: String
  name_in?: String[] | String
  name_not_in?: String[] | String
  name_lt?: String
  name_lte?: String
  name_gt?: String
  name_gte?: String
  name_contains?: String
  name_not_contains?: String
  name_starts_with?: String
  name_not_starts_with?: String
  name_ends_with?: String
  name_not_ends_with?: String
  description?: String
  description_not?: String
  description_in?: String[] | String
  description_not_in?: String[] | String
  description_lt?: String
  description_lte?: String
  description_gt?: String
  description_gte?: String
  description_contains?: String
  description_not_contains?: String
  description_starts_with?: String
  description_not_starts_with?: String
  description_ends_with?: String
  description_not_ends_with?: String
  price?: Int
  price_not?: Int
  price_in?: Int[] | Int
  price_not_in?: Int[] | Int
  price_lt?: Int
  price_lte?: Int
  price_gt?: Int
  price_gte?: Int
  location?: String
  location_not?: String
  location_in?: String[] | String
  location_not_in?: String[] | String
  location_lt?: String
  location_lte?: String
  location_gt?: String
  location_gte?: String
  location_contains?: String
  location_not_contains?: String
  location_starts_with?: String
  location_not_starts_with?: String
  location_ends_with?: String
  location_not_ends_with?: String
  condition?: Condition
  condition_not?: Condition
  condition_in?: Condition[] | Condition
  condition_not_in?: Condition[] | Condition
  status?: Status
  status_not?: Status
  status_in?: Status[] | Status
  status_not_in?: Status[] | Status
  expiredAt?: DateTime
  expiredAt_not?: DateTime
  expiredAt_in?: DateTime[] | DateTime
  expiredAt_not_in?: DateTime[] | DateTime
  expiredAt_lt?: DateTime
  expiredAt_lte?: DateTime
  expiredAt_gt?: DateTime
  expiredAt_gte?: DateTime
  soldAt?: DateTime
  soldAt_not?: DateTime
  soldAt_in?: DateTime[] | DateTime
  soldAt_not_in?: DateTime[] | DateTime
  soldAt_lt?: DateTime
  soldAt_lte?: DateTime
  soldAt_gt?: DateTime
  soldAt_gte?: DateTime
  deletedAt?: DateTime
  deletedAt_not?: DateTime
  deletedAt_in?: DateTime[] | DateTime
  deletedAt_not_in?: DateTime[] | DateTime
  deletedAt_lt?: DateTime
  deletedAt_lte?: DateTime
  deletedAt_gt?: DateTime
  deletedAt_gte?: DateTime
  createdAt?: DateTime
  createdAt_not?: DateTime
  createdAt_in?: DateTime[] | DateTime
  createdAt_not_in?: DateTime[] | DateTime
  createdAt_lt?: DateTime
  createdAt_lte?: DateTime
  createdAt_gt?: DateTime
  createdAt_gte?: DateTime
  updatedAt?: DateTime
  updatedAt_not?: DateTime
  updatedAt_in?: DateTime[] | DateTime
  updatedAt_not_in?: DateTime[] | DateTime
  updatedAt_lt?: DateTime
  updatedAt_lte?: DateTime
  updatedAt_gt?: DateTime
  updatedAt_gte?: DateTime
  seller?: UserWhereInput
  likes_every?: ListingLikeWhereInput
  likes_some?: ListingLikeWhereInput
  likes_none?: ListingLikeWhereInput
}

Solution

  • The problem is typescript will not infer string literal types for object literal properties, so the status in will be typed as string not 'ACTIVE'

    You could specify the type for where explicitly:

    const where:ListingWhereInput  = .. 
    

    Or you can use a type assertion for force the property to be of the string literal type

    { status: 'ACTIVE' as  'ACTIVE'}