如何基于函数返回值筛选TypeScript接口中的函数键?
问题分析与解决
先明确核心问题:你写的KeysReturnStrings在传入单个键时正常,但传入keyof MyInterface这类联合类型时返回never,而前缀筛选的KeysNoGet却能处理联合类型,本质是条件类型的分布式行为差异导致的。
为什么原写法失效
当你把联合类型keyof MyInterface传入KeysReturnStrings时,ReturnType<MyInterface[K]>会直接计算成所有返回值的联合类型string | number。此时判断string | number extends string?显然不成立,所以整个条件返回never。
而KeysNoGet能正常工作,是因为它用了分布式条件类型:当条件类型的左侧是裸的类型参数(没有被包裹在数组、对象等类型里),且参数是联合类型时,TypeScript会自动对联合类型的每个成员单独执行条件判断,再把结果合并成新的联合类型。比如KeysNoGet<keyof MyInterface>会逐个检查每个键是否以Get开头,最后合并符合要求的结果。
正确实现方式
要实现基于返回值筛选联合键的需求,有两种简洁的实现方式:
方式一:改造为分布式条件类型
让类型参数K以裸参数形式参与条件判断,触发分布式行为:
type KeysReturnStrings<K extends keyof MyInterface> = K extends keyof MyInterface ? ReturnType<MyInterface[K]> extends string ? K : never : never; type Test3 = KeysReturnStrings<keyof MyInterface>; // "GetChocolate" | "SetVanilla"
方式二:映射类型(更直观)
先通过映射类型遍历所有键,标记符合条件的键,再提取有效结果:
type KeysReturnStrings = { [K in keyof MyInterface]: ReturnType<MyInterface[K]> extends string ? K : never; }[keyof MyInterface]; type Test3 = KeysReturnStrings; // "GetChocolate" | "SetVanilla"
这种方式会先为每个键生成对应的类型(符合条件保留键名,不符合则为never),最后通过[keyof MyInterface]索引访问,自动过滤掉never成员并合并成联合类型。
验证效果
两种方式都能满足需求:
- 传入联合类型时,正确返回
"GetChocolate" | "SetVanilla" - 传入单个键时依然正常工作:
type Test1 = KeysReturnStrings<"GetChocolate">; // "GetChocolate" type Test2 = KeysReturnStrings<"SetChocolate">; // never
内容的提问来源于stack exchange,提问作者Prof.Chewbacca
相关产品推荐
相关产品推荐

