指定泛型后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 }, } } }
验证效果
- 指定资源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"
- 不指定资源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
相关产品推荐
相关产品推荐

