如何断言两个字符串联合类型相等并给出详细差异错误提示?
实现带详细错误提示的路径参数与验证对象类型匹配检查
需求说明
我正在为API框架开发类型守卫,需要将路径参数(字符串)与验证对象关联。
验证对象示例:
const params = { firstArg: someValidationFunction, secondArg: someValidationFunction, }
针对不同路径字符串,期望结果如下:
/api/some/path/{firstArg}/{secondArg}→ 符合要求(两个参数均以正确名称出现在字符串中)/api/some/path/{secondArg}/{firstArg}→ 符合要求(参数顺序不做强制要求)/api/some/path/{someOtherArg}→ 不符合要求(缺少指定参数且存在未知参数)/api/some/path/{firstArg}/{secondArg}/{someOtherArg}→ 不符合要求(存在未知参数)/api/some/path/{firstArg}/secondArg→ 不符合要求(secondArg未加花括号,视为缺失)
当前实现
参考博客实现了提取路径参数的类型工具:
type ExtractPathParams<Path> = Path extends `${infer Segment}/${infer Rest}` ? ExtractParam<Segment, ExtractPathParams<Rest>> : ExtractParam<Path, {}>; type ExtractParam<Path, NextPart> = Path extends `{${infer Param}}` ? Record<Param, any> & NextPart : NextPart;
并通过以下方式断言路径参数类型与验证对象键类型是否相等:
function assert<T extends never>() {} type Equal<A, B> = Exclude<A, B> | Exclude<B, A>; type ValidationKeys = keyof typeof params; const one = '/api/some/path/{firstArg}/{secondArg}'; const two = '/api/some/path/{secondArg}/{firstArg}'; const three = '/api/some/path/{someOtherArg}'; const four = '/api/some/path/{firstArg}/{secondArg}/{someOtherArg}'; const five = '/api/some/path/{firstArg}/secondArg'; assert<Equal<keyof ExtractPathParams<typeof one>, ValidationKeys>>(); assert<Equal<keyof ExtractPathParams<typeof two>, ValidationKeys>>(); // @ts-expect-error assert<Equal<keyof ExtractPathParams<typeof three>, ValidationKeys>>(); // @ts-expect-error assert<Equal<keyof ExtractPathParams<typeof four>, ValidationKeys>>(); // @ts-expect-error assert<Equal<keyof ExtractPathParams<typeof five>, ValidationKeys>>();
问题
当前实现可以判断类型是否相等,但错误提示仅显示泛泛的类型不匹配信息,无法明确指出缺失哪些必填参数或存在哪些未知参数,希望能生成更详细的错误提示。
解决方案
可以通过自定义条件类型,分别计算缺失的键和多余的键,然后在类型不匹配时返回包含具体信息的字符串类型,让TypeScript的错误提示直接展示问题点。
步骤1:优化路径参数提取类型
首先调整ExtractPathParams,让它直接返回路径参数的联合类型(方便后续对比):
type ExtractPathParams<Path> = Path extends `${infer Segment}/${infer Rest}` ? ExtractParam<Segment> | ExtractPathParams<Rest> : ExtractParam<Path>; type ExtractParam<Path> = Path extends `{${infer Param}}` ? Param : never;
步骤2:创建详细错误提示类型
定义类型分别计算缺失的必填键、多余的未知键,并拼接成直观的提示字符串:
type MissingKeys<PathKeys, RequiredKeys> = Exclude<RequiredKeys, PathKeys>; type ExtraKeys<PathKeys, RequiredKeys> = Exclude<PathKeys, RequiredKeys>; type PathValidationError<PathKeys, RequiredKeys> = MissingKeys<PathKeys, RequiredKeys> extends never ? ExtraKeys<PathKeys, RequiredKeys> extends never ? never // 无错误,符合要求 : `路径存在未知参数:${ExtraKeys<PathKeys, RequiredKeys>}` : ExtraKeys<PathKeys, RequiredKeys> extends never ? `路径缺失必填参数:${MissingKeys<PathKeys, RequiredKeys>}` : `路径缺失必填参数:${MissingKeys<PathKeys, RequiredKeys>},同时存在未知参数:${ExtraKeys<PathKeys, RequiredKeys>}`;
步骤3:更新断言与验证逻辑
修改验证逻辑,让错误提示直接展示具体问题:
function assert<T extends never>() {} type ValidationKeys = keyof typeof params; // 封装路径验证的类型工具 type ValidatePath<Path> = PathValidationError<ExtractPathParams<Path>, ValidationKeys>; // 测试用例 assert<ValidatePath<typeof one>>(); // 无错误 assert<ValidatePath<typeof two>>(); // 无错误 // @ts-expect-error 错误提示:路径缺失必填参数:firstArg|secondArg,同时存在未知参数:someOtherArg assert<ValidatePath<typeof three>>(); // @ts-expect-error 错误提示:路径存在未知参数:someOtherArg assert<ValidatePath<typeof four>>(); // @ts-expect-error 错误提示:路径缺失必填参数:secondArg assert<ValidatePath<typeof five>>();
效果说明
现在当路径不符合要求时,TypeScript会直接在错误提示中明确显示:
- 缺失的必填参数列表
- 存在的未知参数列表
- 同时存在两种问题时会一并提示
开发者能快速定位路径中的参数问题,无需猜测类型不匹配的具体原因。
内容的提问来源于stack exchange,提问作者Milton
相关产品推荐
相关产品推荐

