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

仅用TypeScript能否实现对象键路径自动补全及非法路径类型校验?

该需求完全可以仅通过 TypeScript 类型系统实现,不需要额外运行时依赖,核心用到 TypeScript 4.1 版本引入的模板字面量类型、递归条件类型、剩余参数类型推导特性即可完成。

完整实现代码

首先定义通用的路径校验工具类型,再基于工具类型定义目标函数的类型:

/**
 * 递归生成目标对象所有合法的点分隔路径联合类型
 * 例如传入 {a:{b:1}} 会生成 'a' | 'a.b'
 */
type DotPath<T, Prefix extends string = ''> = T extends object 
  ? {
      [K in keyof T & string]: 
        Prefix extends '' 
          ? K | DotPath<T[K], `${K}`>
          : `${Prefix}.${K}` | DotPath<T[K], `${Prefix}.${K}`>
    }[keyof T & string]
  : never

/**
 * 递归生成目标对象所有合法的路径元组联合类型
 * 例如传入 {a:{b:1}} 会生成 ['a'] | ['a', 'b']
 */
type TuplePath<T, Tuple extends string[] = []> = T extends object
  ? {
      [K in keyof T & string]: 
        [...Tuple, K] | TuplePath<T[K], [...Tuple, K]>
    }[keyof T & string]
  : never

/**
 * 绑定指定对象结构的路径校验函数类型
 * 支持两种传参格式:点分隔字符串、多参数拼接路径
 */
type PathValidFn<T> = {
  (path: DotPath<T>): void
  (...path: TuplePath<T>): void
}

使用示例

针对你给出的示例对象,使用效果如下:

const val = {
  a: {
    b: {
      c: 1
    }
  }
}

// 生成适配 val 结构的校验函数
const myFn: PathValidFn<typeof val> = (pathOrFirst: string, ...rest: string[]) => {
  // 这里写你自己的业务运行时逻辑,比如路径拼接、取值、遍历等
  const fullPath = rest.length ? [pathOrFirst, ...rest].join('.') : pathOrFirst
  // 示例:根据路径取值
  const value = fullPath.split('.').reduce((prev, key) => prev[key as keyof typeof prev], val)
  console.log(value)
}

// 合法调用,TS无报错
myFn('a.b.c') 
myFn('a', 'b', 'c')
myFn('a.b')
myFn('a')

// 非法调用,TS会直接标记类型错误
myFn('a.x.c') // 报错:类型"a.x.c"无法分配给类型"a" | "a.b" | "a.b.c"
myFn('a', 'b', 'x') // 报错:类型"x"的参数不能分配给类型"c"的参数

扩展说明

  • 如果需要支持数组下标的路径校验,只需将上述工具类型中的keyof T & string修改为keyof T & (string | number)即可自动适配数字索引
  • 如果需要让函数支持任意对象的路径校验(而非提前绑定固定对象),可以将函数改造为泛型函数,把目标对象作为第一个入参即可:
function myFn<T extends object>(obj: T, path: DotPath<T>): unknown
function myFn<T extends object>(obj: T, ...path: TuplePath<T>): unknown
function myFn<T extends object>(obj: T, pathOrFirst: string, ...rest: string[]) {
  const fullPath = rest.length ? [pathOrFirst, ...rest].join('.') : pathOrFirst
  return fullPath.split('.').reduce((prev, key) => prev[key as keyof typeof prev], obj)
}

// 调用示例
myFn(val, 'a.b.c') // 正常返回1
myFn(val, 'a', 'b', 'c') // 正常返回1
myFn(val, 'a.x') // TS报错

内容的提问来源于stack exchange,提问作者tom10271

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 09:51:00