如何在TypeScript接口中用首个属性值定义第二个属性?含Zod方案
TypeScript 类型实现方案
你遇到的错误是映射类型不能声明属性或方法,原因是映射类型语法中不能直接混合固定属性(比如type: T)和映射字段。可以通过以下两种方式解决:
方式一:交叉类型组合
先定义固定的type属性,再和映射生成的字段做交叉:
type IconType = 'file' | 'emoji' | 'external'; type IconFile<T extends IconType = IconType> = { type: T } & { [K in T]: string }; // 合法示例 const a: IconFile<'file'> = { type: 'file', file: 'foo' }; const b: IconFile<'emoji'> = { type: 'emoji', emoji: 'bar' }; const c: IconFile<'external'> = { type: 'external', external: 'baz' }; // 不指定泛型时,自动兼容所有合法组合 const d: IconFile = { type: 'file', file: 'test' };
方式二:分布式条件类型约束
通过索引访问生成严格的联合类型,确保每个type只对应专属字段:
type IconType = 'file' | 'emoji' | 'external'; type IconFile = { [T in IconType]: { type: T } & Record<T, string> }[IconType]; // 合法示例 const a: IconFile = { type: 'file', file: 'foo' }; // 错误示例:type为file时不能出现emoji字段 const wrong: IconFile = { type: 'file', emoji: 'bar' };
TypeScript + Zod 实现方案
用Zod的discriminatedUnion可以同时实现编译时类型约束和运行时数据校验:
import { z } from 'zod'; // 定义各类型的子校验规则 const fileIconSchema = z.object({ type: z.literal('file'), file: z.string(), }); const emojiIconSchema = z.object({ type: z.literal('emoji'), emoji: z.string(), }); const externalIconSchema = z.object({ type: z.literal('external'), external: z.string(), }); // 基于type字段创建联合校验器 const iconSchema = z.discriminatedUnion('type', [ fileIconSchema, emojiIconSchema, externalIconSchema, ]); // 自动推导TypeScript类型 type IconFile = z.infer<typeof iconSchema>; // 校验测试 iconSchema.parse({ type: 'file', file: 'foo' }); // 成功 iconSchema.parse({ type: 'emoji', emoji: 'bar' }); // 成功 iconSchema.parse({ type: 'external', external: 'baz' }); // 成功 iconSchema.parse({ type: 'file', emoji: 'bar' }); // 抛出校验错误
内容的提问来源于stack exchange,提问作者yuusheng
相关产品推荐
相关产品推荐

