TypeScript静态方法重构报错:keyof T默认类型无法索引T
问题:将Query类重构为含静态方法的命名空间时的TypeScript类型报错
我正尝试重构代码以使用静态方法,因为该类仅用作命名空间,Query.equal<TodoModel>(...) 的写法比 (new Query<TodoModel>).equal(...) 更优。
原有代码如下:
interface TodoModel { title: string; timeLeft: number; done: boolean; } class Query<T> { equal<K extends keyof T>(attr: K, val: T[K]) { return `${String(attr)}==${val}`; } // other methods for notEqual, lessThan, greaterThan, contains etc. } let q = (new Query<TodoModel>) q.equal("unknownKey", 45) // unknownKey gives error q.equal("title", 765) // 765 is the wrong type q.equal("title", "write notes") // no errors
我尝试了以下写法:
class Query2 { static equal<T, K = keyof T>(attr: K, val: T[K]) { return `${String(attr)}==${val}`; } }
这会报错提示“K cannot be used to index type T”,请问原因是什么?是否有解决方案?
我使用默认类型是因为如果用 equal<T, K extends keyof T>,调用时需要写成 Query2.equal<TodoModel, "title">("title", "write notes"),需要重复写key参数。
报错原因
给K设置默认类型为keyof T,但TypeScript不会因为默认值就自动约束K必须是keyof T的子类型。也就是说,调用方法时如果显式传入不属于keyof T的K类型,TypeScript无法保证K能正确索引T,因此抛出该错误。
解决方案
利用TypeScript的类型推断,让编译器从attr参数自动推导K的类型,同时约束K必须是keyof T的子类型,无需显式传入K:
class Query2 { static equal<T, K extends keyof T>(attr: K, val: T[K]) { return `${String(attr)}==${val}`; } }
调用时只需指定T类型,K会自动推导:
// 无需重复传入"title"类型,编译器自动推导K为"title" Query2.equal<TodoModel>("title", "write notes"); // 依然会触发类型检查错误,符合预期 Query2.equal<TodoModel>("unknownKey", 45); // 错误:"unknownKey"不是TodoModel的键 Query2.equal<TodoModel>("title", 765); // 错误:765不是string类型
如果想让调用风格更贴近Query.equal<TodoModel>(...),可以把Query2改成泛型类:
class Query2<T> { static equal<K extends keyof T>(attr: K, val: T[K]) { return `${String(attr)}==${val}`; } } // 调用写法 Query2<TodoModel>.equal("title", "write notes");
这种写法既保留了静态方法的简洁性,又能完整实现原代码的类型检查逻辑。
内容的提问来源于stack exchange,提问作者Nevus
相关产品推荐
相关产品推荐

