在TypeScript中使用导入类型的环境声明

har*_*ryg 28 typescript

我在我的TypeScript项目中有一个声明文件,如下所示:

// myapp.d.ts
declare namespace MyApp {
  interface MyThing {
    prop1: string
    prop2: number
  }
}
Run Code Online (Sandbox Code Playgroud)

这很好用,我可以在项目的任何地方使用这个命名空间,而无需导入它.

我现在需要从第三方模块导入一个类型并在我的环境声明中使用它:

// myapp.d.ts
import {SomeType} from 'module'

declare namespace MyApp {
  interface MyThing {
    prop1: string
    prop2: number
    prop3: SomeType
  }
}
Run Code Online (Sandbox Code Playgroud)

编译器现在抱怨它找不到命名空间'MyApp',大概是因为导入阻止它成为环境.

在使用第三方类型时,是否有一些简单的方法可以保留声明的环境效果?

Rom*_*kov 32

是的,有一种方法.使用import()类型会在TypeScript 2.9中变得更容易,但在早期版本的TypeScript中也是如此.

以下文件是一个脚本.脚本中声明的内容将添加到全局范围.这就是您MyApp.MyThing无需导入即可使用的原因.

// myapp.d.ts
declare namespace MyApp {
  interface MyThing {
    prop1: string;
    prop2: number;
  }
}
Run Code Online (Sandbox Code Playgroud)

脚本是有限的,因为它们不能导入任何东西; 添加时import,脚本将成为模块.我认为至少可以说是奇怪的,但事实就是如此.重要的是模块中定义的内容范围限定为该模块,并且不会添加到全局范围.

但是,模块也可以将声明添加到全局范围中,方法是将它们放入global:

// myapp.d.ts
import {SomeType} from 'module';

declare global {
  namespace MyApp {
    interface MyThing {
      prop1: string;
      prop2: number;
      prop3: SomeType;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

此文件是一个模块,但它MyApp.MyThing向全局范围添加了声明,因此您仍可以使用MyApp.MyThing其他TypeScript代码而无需导入它.

请注意,使用.d.ts扩展名与您无需导入即可访问界面无关.上述两个文件都可能是.ts文件,但仍然表现完全相同.

  • 谢谢你。我一直在寻找这个解决方案一个多小时了。为什么很难与将符号添加到全局范围但无法使用常规模块导入的环境集成,这超出了我的理解,尤其是因为它似乎是一个如此普遍的要求...... (2认同)
  • 将其包装在`global`中确实需要更加知名。这是一个非常常见的情况,许多答案都忽略了此简单的解决方法。 (2认同)
  • 我希望我能对此投赞成票 1000 次。我一直在打结。 (2认同)

seb*_*ian 13

从TS 2.9开始,可以通过以下方式实现import()

// myapp.d.ts
declare type SomeType = import('module').SomeType;
declare type SomeDefaultType = import('module-with-default-export').default;


declare namespace MyApp {
  interface MyThing {
    prop1: string;
    prop2: number;
    prop3: SomeType | SomeDefaultType;
  }
}
Run Code Online (Sandbox Code Playgroud)