【问题标题】:Generated type declarations convert implicit types to any生成的类型声明将隐式类型转换为任何
【发布时间】:2020-12-18 08:01:06
【问题描述】:

我正在开发一个模块,我必须这样做:

    const foo = () => {
        const bar = {
            a: () => bar,

            b: () => bar,

            c: () => bar
        }

        return bar
    }  

    foo().a().b().c()

即使所有类型都是隐式打字稿也很棒并且可以帮助我自动完成。

由于我必须发布到 npm,我让 tsc 生成类型声明,但是这是我在 index.d.ts 文件中得到的:

declare const foo: () => {
    a: () => any;
    b: () => any;
    c: () => any;
};

这意味着安装我的模块的人将无法充分利用 typescript 的优点。

有没有简单的方法来解决这个问题?

【问题讨论】:

    标签: typescript tsc type-declaration


    【解决方案1】:

    您只需要给 TS 编译器一个小提示,帮助您找出类型:

    interface Bar {
      a: () => Bar;
      b: () => Bar;
      c: () => Bar;
    }
    
    const foo = () => {
      const bar: Bar = {
        a: () => bar,
        b: () => bar,
        c: () => bar
      }
    
      return bar
    }
    
    const result = foo().a() // Bar
    

    第二个选项 - 递归方法

    
    type Rec<Bar> = Record<keyof Bar, () => Rec<Bar>>
    
    const foo = () => {
    
      const bar = {
        a: () => bar,
        b: () => bar,
        c: () => bar
      } as const
      type Bar = typeof bar;
      return bar as Rec<Bar>
    }
    
    const result = foo().a().b().b().c(); // Record<"a" | "b" | "c", () => Record<"a" | "b" | "c", ...>>
    

    TS 编译器将any 放在这里:

    declare const result: Readonly<Record<"a" | "b" | "c", () => Readonly<Record<"a" | "b" | "c", any>>>>;
    

    因为它是递归类型。您希望在这里看到什么?

    declare const result: Record<"a" | "b" | "c", () => Record<"a" | "b" | "c",  () => Record<"a" | "b" | "c", () => Record<"a" | "b" | "c", () => Record<"a" | "b" | "c", () => Record<"a" | "b" | "c", () => Record<"a" | "b" | "c",any>>>>>>>;
    // ... Infinity
    

    TS 应该停在某处)

    【讨论】:

    • 我知道这会起作用,但这对我来说有点问题,因为我不仅有 a、b 和 c,而是有大约 30 个具有不同输入签名的函数,并且这种模式在几个文件中重复出现。另外,每次修改函数都要更新接口,好像违反了DRY。
    • 第二个选项很有趣,然而,生成的 index.d.ts 文件看起来像这样: declare type Rec = Record Rec>;声明 const foo: () => Record 记录>;末尾的 any 会导致原始问题
    • @Sarrio 是真的,有any,但你永远不会以any 结束
    • @Sarrio 我想,你不能将bar 移出foo 的范围,对吗?
    • 实际上any 是有问题的:我只是尝试将它发布到npm 并将包安装到另一个模块中,如果我这样做const test = foo().a() 然后test 的类型是any 和我不能再使用自动完成功能了。但是,如果我在原始包中做同样的事情,那么它可以工作,我猜这是因为打字稿直接解释原始 .ts 文件并理解递归,但是当导入另一个包时它只会查找 .d.ts包含打破自动完成的any 的文件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-19
    • 2016-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-08
    • 1970-01-01
    相关资源
    最近更新 更多