这可行,但我确信有更好的方法可以做到这一点,我使用 zod 对用户零控制的值进行模式验证。
const SchemaValue = z.object({
translatedValue: z.string().or(z.number())
});
const SchemaInput = z.object({
truncate: z.number()
});
然后我有一个非常简单的类,它采用这些模式并执行验证,并将类型推断回传递给“操作”的方法。
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,
);
}
}
然后我像这样使用它:
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];
}
});
这是可行的,验证器上输入和值的智能感知是正确的,但是我忍不住认为有一种更好的方法可以实现这一点,而不必将类型传递给构造函数,我问的唯一原因是我我正在努力使
Action
的使用尽可能简单!
我想知道是否有一种方法可以从 inputSchema 和 valueSchema 推断类型,而无需在调用新实例时通过构造函数传递它们?
z.AnyZodObject
不是通用的,会删除任何自动推理。
使用
z.Schema<T>
自动推断类型,因为它是泛型。
...
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];
}
});
只要您不使用
zod
的更高级功能(例如 .optional().default(1)
),上述解决方案就有效。如果您是,这里有一个适用于上述操作和变革操作的替代方案。
const OptionalValue = z.object({
translatedValue: z.number().optional().default(1),
});
function validateIncorrect<T>(schema: z.Schema<T>, value: unknown, callback: (validatedValue: T) => void) {
const validatedValue = schema.parse(value);
return callback(validatedValue);
}
validateIncorrect(OptionalValue, { translatedValue: 2 }, (v) => {
// incorrect
// { translatedValue?: number | undefined; }
console.log(v);
});
function validateCorrect<T extends z.AnyZodObject>(schema: T, value: unknown, callback: (validatedValue: z.infer<T>) => void) {
const validatedValue = schema.parse(value);
return callback(validatedValue);
}
validateCorrect(OptionalValue, { translatedValue: 2 }, (v) => {
// correct
// { translatedValue: number; }
console.log(v);
});