TypeScript泛型map函数类型标注报错求助
问题描述
在TypeScript Exercises第14题中,需要为以下无类型标注的函数添加严格的TypeScript类型:
export function map(mapper, input) { if (arguments.length === 0) { return map; } if (arguments.length === 1) { return function subFunction(subInput) { if (arguments.length === 0) { return subFunction; } return subInput.map(mapper); }; } return input.map(mapper); }
我尝试用泛型定义类型但失败了,我的代码如下:
type Apply<In, Out> = (element: In) => Out; declare function subFunction<In2, Out2>(subInput: In2[]): Out2[]; declare function subFunction(): typeof subFunction; export function map<In, Out>(): typeof map; export function map<In, Out>(mapper: Apply<In, Out>): typeof subFunction; export function map<In, Out>(mapper: Apply<In, Out>, input: In[]): Out[]; export function map<In, Out>(mapper?: Apply<In, Out>, input?: In[]): ((typeof map) | (typeof subFunction) | Out[]) { if (mapper === undefined) { return map; } if (input === undefined) { // 第61行报错 return function subFunction(subInput?: In[]): ((typeof subFunction) | Out[]) { if (subInput === undefined) { return subFunction; } return subInput.map(mapper); }; } return input.map(mapper); }
报错信息:
index.ts(61,9): error TS2322: Type '(subInput?: In[] | undefined) => Out[] | ...' is not assignable to type '{ <In2, Out2>(subInput: In2[]): Out2[]; (): typeof subFunction; } | { <In, Out>(): typeof map; <In, Out>(mapper: Apply<In, Out>): { <In2, Out2>(subInput: In2[]): Out2[]; (): typeof subFunction; }; <In, Out>(mapper: Apply<...>, input: In[]): Out[]; } | Out[]'. Type '(subInput?: In[] | undefined) => Out[] | ...' is not assignable to type '{ <In2, Out2>(subInput: In2[]): Out2[]; (): typeof subFunction; }'. Type 'Out[] | ((subInput?: In[] | undefined) => Out[] | ...)' is not assignable to type 'any[]'. Type '(subInput?: In[] | undefined) => Out[] | ...' is missing the following properties from type 'any[]': pop, push, concat, join, and 25 more.
当我把第61行subFunction的返回类型改为any时错误消失,请问我哪里错了?
错误原因与修正方案
核心错误点
你定义的subFunction是通用泛型函数,但实际返回的subFunction已经绑定了外部的mapper(固定了In和Out类型),两者类型不匹配:
- 声明的
subFunction<In2, Out2>可以接受任意类型数组并返回对应类型数组,是无绑定的泛型 - 但代码中返回的
subFunction只能接受In[]类型输入,返回Out[],同时支持无参调用返回自身,是绑定了特定类型的专用函数
另外,map的返回类型写的(typeof map) | (typeof subFunction) | Out[]也不准确,因为只传mapper时返回的不是全局声明的通用subFunction,而是绑定了In/Out的专用函数。
正确的类型定义写法
我们需要为绑定后的subFunction定义专用类型,而非复用通用泛型声明:
方案一:用类型别名明确绑定关系
type Apply<In, Out> = (element: In) => Out; // 定义绑定了In/Out类型的子函数类型 type BoundSubFunction<In, Out> = { (): BoundSubFunction<In, Out>; (subInput: In[]): Out[]; }; // 定义map函数的完整重载类型 type MapFunction = { <In, Out>(): MapFunction; <In, Out>(mapper: Apply<In, Out>): BoundSubFunction<In, Out>; <In, Out>(mapper: Apply<In, Out>, input: In[]): Out[]; }; export const map: MapFunction = function map(mapper?: any, input?: any) { if (arguments.length === 0) { return map; } if (arguments.length === 1) { return function subFunction(subInput?: any) { if (arguments.length === 0) { return subFunction; } return subInput.map(mapper); }; } return input.map(mapper); };
方案二:直接用函数重载实现
type Apply<In, Out> = (element: In) => Out; export function map(): typeof map; export function map<In, Out>(mapper: Apply<In, Out>): { (): ReturnType<typeof map<In, Out>>; (subInput: In[]): Out[]; }; export function map<In, Out>(mapper: Apply<In, Out>, input: In[]): Out[]; export function map(mapper?: any, input?: any) { if (arguments.length === 0) { return map; } if (arguments.length === 1) { return function subFunction(subInput?: any) { if (arguments.length === 0) { return subFunction; } return subInput.map(mapper); }; } return input.map(mapper); }
关键细节
- 只传入
mapper时,返回的函数已经固定了输入输出类型,不能再用通用的<In2, Out2>泛型,必须绑定到外部的In和Out - 重载签名要精确匹配函数行为:无参返回自身,单参返回绑定后的子函数,双参直接返回映射后的数组
- 实现部分用
any兼容即可,因为重载签名已经提供了严格的外部类型检查,内部实现的类型宽松不影响调用体验
内容的提问来源于stack exchange,提问作者Yam Mesicka
相关产品推荐
相关产品推荐

