Pothos
Guide

Inferring Types

In some cases you may want to use the types from your input or object refs to build helpers, or provide accurate types for other functions.

To get types from any Pothos ref object, you can use the $inferType and $inferInput properties on the corresponding output or input ref. Use these properties in TypeScript type expressions, not to read runtime data. An object ref carries its backing model, not a GraphQL query result: clients select fields, and resolvers can expose fields that are not properties of the backing model.

import SchemaBuilder from '@pothos/core';

const builder = new SchemaBuilder({});

const MyInput = builder.inputType('MyInput', {
  fields: (t) => ({
    id: t.id({ required: true }),
    name: t.string({ required: true }),
  }),
});

// { id: string; name: string; }
type MyInputShape = typeof MyInput.$inferInput;

const UserRef = builder.objectRef<{ id: string; name: string }>('User').implement({
  fields: (t) => ({
    id: t.exposeID('id'),
    name: t.exposeString('name'),
  }),
});
type UserType = typeof UserRef.$inferType;

When building helpers, most Pothos types have a generic called Types that extends SchemaTypes. This combines all the defaults and settings passed in when creating the SchemaBuilder. To make your own type helpers and utility functions, you often need access to the Types used by your builder.

This can be inferred from the builder using typeof builder.$inferSchemaTypes.

The following is a simple helper for creating objects that have an id field. The helper itself isn't that useful, but shows how inferring SchemaTypes from a builder can work.

import type { FieldMap } from '@pothos/core';

type BuilderTypes = typeof builder.$inferSchemaTypes;

function createObjectWithId<T extends { id: string }>(
  name: string,
  fields: (t: PothosSchemaTypes.ObjectFieldBuilder<BuilderTypes, T>) => FieldMap,
) {
  const ref = builder.objectRef<T>(name);

  ref.implement({
    fields: (t) => ({
      ...fields(t),
      id: t.id({
        resolve: (parent) => parent.id,
        nullable: false,
      }),
    }),
  });

  return ref;
}

const UserWithId = createObjectWithId<{
  id: string;
  name: string;
}>('UserWithId', (t) => ({
  name: t.exposeString('name'),
}));

Rather than explicitly using the inferred type, you can also infer SchemaTypes from the builder in an argument. In the following example, we pass in the builder to the createPaginationArgs, and infer the Types from the provided builder. This is useful when building helpers that might be used with multiple builder instances.

import type { SchemaTypes } from '@pothos/core';

function createPaginationArgs<Types extends SchemaTypes>(
  builder: PothosSchemaTypes.SchemaBuilder<Types>,
) {
  return builder.args((t) => ({
    limit: t.int(),
    offset: t.int(),
  }));
}

builder.queryType({});

builder.queryField('getUsers', (t) =>
  t.field({
    type: [UserWithId],
    args: {
      ...createPaginationArgs(builder),
    },
    resolve: () => [],
  }),
);