Home > Net >  How create type guard for path with dynamic field?
How create type guard for path with dynamic field?

Time:07-03

I have a field that can contain both a schema and an object in which this schema lies by key, depending on the situation

How should looks a guard be able to solve this problem?

Here is example of my code

import * as z from 'zod';
import type { ZodTypeAny } from 'zod'

type Key = 'test' | 'test2' | 'test3'

type Schema = {
  schema?: ZodTypeAny |  {
    [Property in Key]?: ZodTypeAny
  }
}

const userSchema = z.object({
  name: z.string(),
  email: z.string(),
});


const getSchema = (key: Key, path: Schema) {
  return path.schema?.[key] || path.schema
}

getSchema('test', { schema: {'test':  userSchema}})
getSchema('test', { schema: userSchema})

and of course you can test it in TS payground link

CodePudding user response:

Not familiar with Zod but I believe this captures your intent:

import * as z from 'zod';
import type { ZodTypeAny } from 'zod'

type Key = 'test' | 'test2' | 'test3'

type SchemaObject = {
    [Property in Key]?: ZodTypeAny
}

type Schema = {
  schema?: ZodTypeAny | SchemaObject
}

const userSchema = z.object({
  name: z.string(),
  email: z.string(),
});

function isSchemaObject(z: Schema['schema']): z is SchemaObject {
  return Object.prototype.hasOwnProperty.call(z, 'test')
    || Object.prototype.hasOwnProperty.call(z, 'test2') 
    || Object.prototype.hasOwnProperty.call(z, 'test3') 
}

const getSchema = (key: Key, path: Schema) => {
  const schema = path.schema;
  return isSchemaObject(schema) ? schema[key] : schema
}

getSchema('test', { schema: {'test':  userSchema}})
getSchema('test', { schema: userSchema})

So we create a SchemaObject type to simplify referring to it, and then use a type guard isSchemaObject to check which of the components of the union type the value is.

CodePudding user response:

You can add a type predicate to check if schema is ZodType<any, any, any>. Something like this

const isSchemaZodType = (schema: unknown): schema is ZodTypeAny => schema instanceof z.ZodType<any, any, any>

and then use it like this

const getSchema = (key: Key, path: Schema) => {
  if (!path.schema) {
    return path
  }

  if (isSchemaZodType(path.schema)) {
    return path.schema
  }

  return path.schema[key]
}

Playground here

  • Related