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

指定泛型后TypeScript类型安全失效,如何兼顾资源Schema校验?

问题解决:同时保证actionKey类型安全与资源对象Schema校验

问题核心是:当显式指定R泛型时,原代码中D的类型被默认的Definition<R>(即actions: Record<string, number>)覆盖,导致keyof D['actions']退化为宽泛的string,失去了字面量类型的校验能力。

修改方案

调整泛型定义,让actions的具体键类型能被正确推断,同时保留对资源对象R的Schema约束:

// 重新定义Definition,用Actions捕获具体的actions对象类型
type Definition<Actions extends Record<string, number>> = {
  actions: Actions
}

export function defineResource<R extends object = object, Actions extends Record<string, number>>(
  definition: Definition<Actions>
) {
  return (resource: R) => {
    return {
      // 直接使用Actions的键作为actionKey的类型约束
      can(user: any, actionKey: keyof Actions) {
        return true
      },
    }
  }
}

验证效果

  1. 指定资源Schema场景:
const myResource = defineResource<{ something: number }>({
    actions: {
        create: 100,
        delete: 100,
    }
})

myResource({ something: 123 }).can({}, 'test') // TypeScript报错:"test"不能赋值给"create" | "delete"
myResource({ something: 123 }).can({}, 'create') // 正常通过校验
myResource({ wrongKey: 456 }) // 报错:缺少属性"something"
  1. 不指定资源Schema场景:
const anotherResource = defineResource({
    actions: {
        update: 200,
        read: 300,
    }
})

anotherResource({ id: 1 }).can({}, 'update') // 正常通过
anotherResource({ id: 1 }).can({}, 'invalid') // 报错:"invalid"不符合"update" | "read"

原理说明

  • 将Definition的泛型参数从R改为Actions,让Actions捕获传入的actions对象的具体字面量键类型,而非宽泛的string。
  • 函数泛型中先指定R用于约束资源对象结构,Actions由传入的definition自动推断,既保留了资源Schema的校验能力,又保证了actionKey只能是actions中定义的合法键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 11:47:22