TypeScript 中泛型“map”函数的类型声明

Type declaration of a generic `map` function in TypeScript

提问人:Yam Mesicka 提问时间:7/17/2022 最后编辑:STerliakovYam Mesicka 更新时间:7/19/2022 访问量:309

问:

打字稿练习的练习 #14 中,您可以注释以下函数:

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) {
        // Line 61 (the error) ahead
        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.

当我将 @ line 61 的返回类型更改为 时,错误消失了。subFunctionany

我做错了什么?

TypeScript 泛型 函数式编程 闭包 类型化

评论


答:

1赞 Ryan Pattillo 7/17/2022 #1

我认为问题出在关键字的使用上。我不确定问题的确切出处,但此处未正确使用关键字。它应该用于通知编译器存在一个名为 subFunction 的函数,但事实并非如此,因为实际上是在 中声明的。declaresubFunctionmap

您可以通过将声明替换为我在这里调用的另一个声明来解决此问题。typeSubMap<In, Out>

type Apply<In, Out> = (element: In) => Out;
type SubMap<In, Out> = (subInput?: In[]) => SubMap<In, Out> | Out[];

export function map<In, Out>(): SubMap<In, Out>;
export function map<In, Out>(mapper: Apply<In, Out>): SubMap<In, Out>;
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 | SubMap<In, Out> | Out[]
{
    if (mapper === undefined)
    {
        return map;
    }
    if (input === undefined)
    {
        return function subFunction(subInput?: In[]): SubMap<In, Out> | Out[]
        {
            if (subInput === undefined)
            {
                return subFunction;
            }
            return subInput.map(mapper);
        };
    }
    return input.map(mapper);
}

另一种选择是在 之外实际创建,尽管这需要一些重构。subFunctionmap

type Apply<In, Out> = (element: In) => Out;

function subFunction<In, Out>(mapper: Apply<In, Out>): typeof subFunction;
function subFunction<In, Out>(mapper: Apply<In, Out>, subInput: In[]): typeof subFunction | Out[];

function subFunction<In, Out>(mapper: Apply<In, Out>, subInput?: In[]): typeof subFunction | Out[]
{
    if (subInput === undefined)
    {
        return subFunction;
    }
    return subInput.map(mapper);
}

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)
    {
        return subFunction(mapper);
    }
    return input.map(mapper);
}