This works, but I'm sure there's a nicer way of doing this, I'm using zod for schema validation on values i have zero control over from the user.
const SchemaValue = z.object({
translatedValue: z.string().or(z.number())
});
const SchemaInput = z.object({
truncate: z.number()
});
I then have a very simple class, which takes those schemas and performs validation, and also infers the type back to a method passed to the "Action".
interface ActionOptions<I, V> {
name: string;
inputSchema: z.AnyZodObject;
valueSchema: z.AnyZodObject;
validator: (input: I, value: V) => Promise<[string | null, boolean]>;
}
export class Action<I, V> {
options: ActionOptions<I, V>;
constructor(options: ActionOptions<I, V>) {
this.options = options;
}
async run(value: V, input: I): Promise<void> {
// additional code is here to validate value & input against valueSchema and inputSchema
await this.options.validator(
input,
value,
);
}
}
I then use this like so:
const action = new Action<z.infer<typeof InputSchema>, z.infer<typeof ValueSchema>>({
inputSchema: InputSchema,
valueSchema: ValueSchema,
name: 'someAction',
async validator(input, value) {
return [null, true];
}
});
This works, intellisense on validator for input & value is correct, however I just can't help but think there's a nicer way of achieving this without having to pass through the types to the constructor, the only reason I'm asking is I'm trying to make the use of Action
as simple as possible!
I'm wondering if there's a way to infer the types from inputSchema and valueSchema without passing them through the constructor when calling a new instance?
CodePudding user response:
The problem
z.AnyZodObject
is not a generic and erases any automatic inference.
The solution
Use z.Schema<T>
to automatically infer the type since it is a generic.
Example
...
interface ActionOptions<I, V> {
name: string;
inputSchema: z.Schema<I>;
valueSchema: z.Schema<V>;
validator: (input: I, value: V) => Promise<[string | null, boolean]>;
}
...
const action = new Action({
inputSchema: InputSchema,
valueSchema: ValueSchema,
name: 'someAction',
async validator(input, value) {
return [null, true];
}
});