能否使用keyof typeof操作符结合数字枚举动态调用TypeScript类静态函数?
keyof typeof实现类静态函数的动态调用? 场景与问题描述
我想通过索引器动态调用类的静态函数,现有代码如下:
定义静态函数的类(Comparer.ts)
class Comparer { static strings(a: string, b: string) { return a.localeCompare(b); } static numbers(a: number, b: number) { return a > b ? 1 : a < b ? -1 : 0; } }
对应函数的数字枚举(Comparers.ts)
enum Comparers { strings, numbers, }
尝试的调用代码(index.ts)
type ComparerKey = keyof typeof Comparer; const result = Comparer[Comparers.strings as ComparerKey]("a", "b"); console.log(result);
出现的错误
This expression is not callable.
Not all constituents of type 'Comparer | ((a: string, b: string) => number) | ((a: number, b: number) => 1 | -1 | 0)' are callable.
Type 'Comparer' has no call signatures.ts(2349)
Conversion of type 'Comparers' to type '"prototype" | "strings" | "numbers"' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.ts(2352)
我理解问题出在:keyof typeof会包含不可调用的prototype成员,同时数字枚举值无法直接转换为类的静态成员键类型。
我已知一种无需keyof typeof的方案——使用字符串枚举:
enum Comparers { strings = "strings", numbers = "numbers", } const result = Comparer[Comparers.strings]("a", "b"); // 无报错 console.log(result);
问题:在该场景下,是否可以使用keyof typeof操作符实现静态函数的调用?
解决方案
可以实现,核心是缩小类型范围并正确处理枚举到键的类型转换:
1. 定义仅包含可调用静态方法的键类型
使用Exclude工具类型排除keyof typeof Comparer中的非函数成员(比如prototype):
type CallableComparerKey = Exclude<keyof typeof Comparer, "prototype">;
2. 处理数字枚举到键类型的转换
数字枚举的枚举值是数字类型,直接转换为字符串键类型会触发类型检查错误,需要先转成unknown再转目标类型:
const result = Comparer[Comparers.strings as unknown as CallableComparerKey]("a", "b");
3. 完整可运行示例
class Comparer { static strings(a: string, b: string) { return a.localeCompare(b); } static numbers(a: number, b: number) { return a > b ? 1 : a < b ? -1 : 0; } } enum Comparers { strings, numbers, } // 仅保留可调用的静态方法键 type CallableComparerKey = Exclude<keyof typeof Comparer, "prototype">; // 动态调用示例 const stringCompareResult = Comparer[Comparers.strings as unknown as CallableComparerKey]("a", "b"); console.log(stringCompareResult); // 输出 1 const numberCompareResult = Comparer[Comparers.numbers as unknown as CallableComparerKey](3, 2); console.log(numberCompareResult); // 输出 1
可选:添加枚举类型验证
如果需要确保枚举的键和类的静态方法名完全匹配,可以添加类型验证:
// 验证枚举的每个键是否都对应可调用的静态方法 type VerifyComparerEnum = { [K in keyof typeof Comparers]: K extends CallableComparerKey ? true : never; }; // 若枚举中添加了不在CallableComparerKey中的键,此处会触发类型错误
内容的提问来源于stack exchange,提问作者OfirD

