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