Moussa Harajli
Moussa Harajli

Reputation: 1516

Typescript: Infer Zod schema type in nested object

I have a simple helper function to capture a type for a configuration object. The configuration object has a couple restrictions:

  1. The getNextStep function may only return a key for another step in the configuration. (This is working).
  2. Each configuration step contains an optional zod schema.

I need to infer the type of the zod schema so that getNextStep is aware of the data for that particular step. No matter how I try to capture the generic for the zod schema, it always resolves to z.ZodType

import { z } from "zod";

type Config<TKey extends string> = {
  [K in TKey]: {
    id: string;
    getNextStep?: (
      data?: unknown <--- Infer this type from the provided schema, if available.
    ) => TKey extends infer U extends string ? Exclude<U, K> | null : never;
    schema?: z.ZodType;
  };
};

function createConfig<TKey extends string>(config: Config<TKey>) {
  return config;
}

const Config = createConfig({
  Step1: {
    id: "Step1",
    schema: z.object({ name: z.string() }),
    getNextStep: () => "Step2",
  },
  Step2: {
    id: "Step2",
    schema: z.object({ enabled: z.boolean() }),
  },
});

Upvotes: 0

Views: 24

Answers (1)

Moussa Harajli
Moussa Harajli

Reputation: 1516

I was able to achieve what I wanted with the following type:

import { z } from "zod";

function createConfig<
  TSchema extends z.ZodType,
  TConfig extends Record<string, TSchema>
>(config: {
  [K in keyof TConfig]: {
    id: string;
    schema?: TConfig[K];
    getNextStep?: (
      data?: z.infer<TConfig[K]>
    ) => Exclude<keyof TConfig, K> | null;
  };
}) {
  return config;
}

const Config = createConfig({
  Overview: {
    id: "Overview",
    schema: z.object({ name: z.string() }),
    getNextStep: (data) => "Main",
  },
  Main: {
    id: "Main",
    schema: z.object({ enabled: z.boolean() }),
  },
});

Upvotes: 0

Related Questions