You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何断言两个字符串联合类型相等并给出详细差异错误提示?

实现带详细错误提示的路径参数与验证对象类型匹配检查

需求说明

我正在为API框架开发类型守卫,需要将路径参数(字符串)与验证对象关联。

验证对象示例:

const params = {
  firstArg: someValidationFunction,
  secondArg: someValidationFunction,
}

针对不同路径字符串,期望结果如下:

  1. /api/some/path/{firstArg}/{secondArg} → 符合要求(两个参数均以正确名称出现在字符串中)
  2. /api/some/path/{secondArg}/{firstArg} → 符合要求(参数顺序不做强制要求)
  3. /api/some/path/{someOtherArg} → 不符合要求(缺少指定参数且存在未知参数)
  4. /api/some/path/{firstArg}/{secondArg}/{someOtherArg} → 不符合要求(存在未知参数)
  5. /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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 20:25:57