如何用Zod创建支持预定义字符串值的字符串类型?
解决Zod中属性同时接受预定义字符串和任意字符串的问题
你的核心需求是让一个属性既能匹配预定义的字符串字面量(保留智能提示),又能接受任意字符串,同时解决调用includes时的类型错误。下面是具体的解决方案:
问题根源
你原来的Zod写法中,z.string().and(z.object({}))是冗余操作,会把字符串类型强制转为string & {},和枚举类型联合后,变量类型变成(string & {}) | TStaticValues。当调用PREDEFINED_VALUES.includes()时,TypeScript认为string & {}无法赋值给预定义的字面量类型,因此报错。
正确的Zod实现方式
方法1:用z.enum().or(z.string())(推荐)
这种写法最简单,既能保留预定义值的智能提示,又允许任意字符串输入,生成的类型本质是string但编辑器会优先提示预定义选项:
const PREDEFINED_VALUES = ['value1', 'value2', 'value3'] as const; type TStaticValues = typeof PREDEFINED_VALUES[number]; const mySchema = z.object({ stringWithPredefinedValues: z.enum(PREDEFINED_VALUES).or(z.string()) }); // 提取类型供业务代码使用 type MyType = z.infer<typeof mySchema>;
方法2:自定义类型复刻原TypeScript逻辑
如果你想严格对齐自己原来的TypeScript类型(string & Record<string, unknown>) | TStaticValues,可以用Zod的z.custom实现:
const PREDEFINED_VALUES = ['value1', 'value2', 'value3'] as const; type TStaticValues = typeof PREDEFINED_VALUES[number]; type Values = (string & Record<string, unknown>) | TStaticValues; const mySchema = z.object({ stringWithPredefinedValues: z.custom<Values>((val) => { return typeof val === 'string'; }, { message: '必须为字符串类型' }) });
解决includes的类型错误
不管用哪种Zod写法,直接调用PREDEFINED_VALUES.includes()都会因为类型不兼容报错,有两种解决方式:
方式1:类型断言
直接将变量断言为string或TStaticValues:
const parsed = mySchema.parse({ stringWithPredefinedValues: 'test' }); const testValue = parsed.stringWithPredefinedValues; // 断言为string(通用场景) const check = PREDEFINED_VALUES.includes(testValue as string); // 若确定值在预定义列表中,可断言为TStaticValues const check2 = PREDEFINED_VALUES.includes(testValue as TStaticValues);
方式2:扩展数组类型声明
通过全局类型扩展,让数组的includes方法接受更宽泛的字符串类型:
declare global { interface Array<T> { includes(searchElement: string | T, fromIndex?: number): boolean; } } // 之后调用不再报错 const check = PREDEFINED_VALUES.includes(testValue);
内容的提问来源于stack exchange,提问作者Echo
相关产品推荐
相关产品推荐

