从TypeScript中的依赖项访问类型声明

时间:2019-05-16 04:22:41

标签: node.js typescript typescript-typings

这是Node.js控制台命令解析器arg的类型:

declare const flagSymbol: unique symbol;

declare function arg<T extends arg.Spec>(spec: T, options?: arg.Options): arg.Result<T>;

declare namespace arg {
    export function flag<T>(fn: T): T & { [flagSymbol]: true };

    export const COUNT: Handler<number> & { [flagSymbol]: true };

    export type Handler <T = any> = (value: string, name: string, previousValue?: T) => T;

    export interface Spec {
        [key: string]: string | Handler | [Handler];
    }

    export type Result<T extends Spec> = { _: string[] } & {
        [K in keyof T]?: T[K] extends Handler
            ? ReturnType<T[K]>
            : T[K] extends [Handler]
            ? Array<ReturnType<T[K][0]>>
            : never
    };

    export interface Options {
        argv?: string[];
        permissive?: boolean;
        stopAtPositional?: boolean;
    }
}

export = arg;

我需要注释解析结果:

import parseConsoleArgument from 'arg';

export function cli(rawConsoleCommandData: Array<string>): void {
  const consoleCommandArguments: /* ??? */ = parseConsoleArgument(
      {}, { argv: rawConsoleCommandData.slice(2)}
  );
}

逻辑上正确的类型是arg.Result。但是,我无法访问它。下面的代码

import parseConsoleArgument from 'arg';

export function cli(rawConsoleCommandData: Array<string>): void {
  const consoleCommandArguments: arg.Result = parseConsoleArgument(
      {}, { argv: rawConsoleCommandData.slice(2)}
  );
}

给予TS2503: Cannot find namespace "arg"

1 个答案:

答案 0 :(得分:1)

不确定为什么要注释变量,它将根据parseConsoleArgument的结果来推断其类型。因此它将已经是适当的类型。如果您的团队要求在所有变量上都添加注释,则您应该挑战IMO,如果不复制大量代码,则很难注释很多类型。这是其中一种情况,让我们看看原因。

访问Result并不是问题,您只是不通过arg命名空间访问它,而是需要通过使用的模块别名来访问它:

const consoleCommandArguments: parseConsoleArgument.Result<{}> = parseConsoleArgument(
    {}, { argv: rawConsoleCommandData.slice(2)}
);

这有效,但是您看到您使用了parseConsoleArgument.Result的{​​{1}}的类型参数。在您开始添加要解析的参数之前,这似乎不是问题:

{}

如果我们删除显式注释,则不会出现错误,并且export function cli(rawConsoleCommandData: Array<string>): void { const consoleCommandArguments: parseConsoleArgument.Result<{}> = parseConsoleArgument( { p: Number, p2: Boolean }, { argv: rawConsoleCommandData.slice(2)} ); consoleCommandArguments.p // err } 是一个p,正如人们所期望的那样。发生这种情况是因为number是一个通用函数,该函数从其第一个参数中提取类型信息,并使用条件类型来创建具有parseConsoleArgument

的新类型。

如果要手动键入此内容,则需要编写:

{ p: number, p2: Boolean }

哪个可以工作,但丑陋,并且比原来的长得多(不必要),并且要求我们更改两个位置以添加新参数。我会让编译器推断类型,这是相当不错的。任何想要查看实际类型的人都可以将鼠标悬停在变量上,他们会在工具提示中看到该类型