You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 22:36:28