【问题标题】:How to get VS Code / typescript autocomplete without importing the library如何在不导入库的情况下获得 VS Code / typescript 自动完成
【发布时间】:2019-10-05 00:40:34
【问题描述】:

如果模块(例如 moment.jsknockoutbig.js)包含在 <script> 标签中,例如

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js">
</script>

定义一个全局属性(例如momentkoBig 等),如何在 Typescript 中访问/声明window(或global)上的类型。

例如

const x = moment()
const t = ko.observable()
const b = new Big()

如何在不包括整个 moment.js 库的情况下设置这些全局变量的环境类型?目标是让 VS Code 和 tscts-loaderbabel-typescript 使用正确类型的全局引用。

对于moment,类型在node_modules/moment/moment.d.ts 公开,但对于其他库(例如knockoutbig.js),它们在@types/[module]/index.d.ts

感觉这很常见,但我还没有看到一个很好的工作参考来说明如何完成这个。


这里是 tsconfig:

{
    "compilerOptions": {
      "target": "ESNext",
      "moduleResolution": "node",
      "allowJs": true,
      "noEmit": true,
      "strict": false,
      "isolatedModules": false,
      "esModuleInterop": true,
      "noResolve": false,
      "baseUrl": ".",
      "paths": {
        "*": [
          "*",
          "js.packages/*"
        ]
      },
      "jsx": "preserve",
      "outDir": "dist/"
  },
  "include": [
    "js.packages/**/*.ts",
    "js.packages/**/*.tsx",
    "js.packages/@types/lib.d.ts",
  ],
  "files": [
    "services/app/src/entry.js"
  ],
  "exclude": [
    "node_modules"
  ]
}

这是lib.d.ts

declare global {
  type Bigable = Big | string | number
  interface Window {
    Big: typeof import('big.js'),
    moment: typeof import('moment'),
    Sentry: typeof import('@sentry/browser'),
  }
}

这是消费应该如何运作的:

const v = new Big(1)
const m = moment()
const s = global.Sentry()
const o = ko.observable()

在 VS Code 中看起来像这样(红色下划线表示失败):

所以淘汰赛有效,因为@types/knockout/index.d.ts 有:

declare var ko: KnockoutStatic;
declare module "knockout" {
    export = ko;
}

而我同样在interface Window 上声明了一个全局Big

不幸的是,Sentrymoment(在此示例中)似乎不起作用,目前尚不清楚为什么或需要做什么来解决此问题。

【问题讨论】:

  • 由于所有类型都是 UMD 声明,并且由于 TypeScript 会自动查找 node_modules/[package]node_modules/@types/[package],因此您不需要做任何特别的事情。请发布您的tsconfig.json。完全可以安装 moment 包来获取类型,同时仍然在运行时从脚本标签加载实现。
  • @AluanHaddad 我已经发布了很多细节,希望能帮助阐明。
  • @TitianCernicova-Dragomir 谢谢;这也是一个很好的问题,你可以从我所做的编辑中看到具体问题的答案是如何不足的。
  • 您能否举例说明您想要做什么(即使用情况)?

标签: typescript


【解决方案1】:

您有正确的想法,您需要使用import 类型来获取导入中的类型,您需要在global 中声明变量。问题是您在Window 上声明属性。虽然分配给 Window 的任何键都变成了全局变量 typescript 并没有反映这一点。您可以直接在全局范围内声明变量。

declare global {
  export var moment: typeof import('moment');
  export var Sentry: typeof import('@sentry/browser');
}

const m = moment()
Sentry.init({}) // Sentry() does not seem like it should work according to docs

【讨论】:

  • 谢谢,这行得通。这在文档或其他任何地方都有说明吗?
  • @BrianM.Hunt 不完全确定.. 有关于声明合并typescriptlang.org/docs/handbook/declaration-merging.html 的文档提到了全局增强。但是 Window 的具体问题我不确定在文档中提到(可能是一些 GH 问题)
【解决方案2】:

这个问题并不是特别针对一种类型的平台,但我会告诉你我是如何让moment 在 Angular 中工作的。

首先,您不应该从脚本 URL 加载。您应该运行 npm install moment 将其放入您的 node_modules 文件夹中。这将确保它被打包到您的应用程序的缩小版本中。您不必这样做,但强烈建议这样做。

"scripts": [
          "node_modules/jquery/dist/jquery.slim.min.js",
          "node_modules/moment/moment.js",
           ...
        ]

不管上述情况如何,一旦你在tsconfig(或angular.json)中链接了脚本,使用就像文件顶部的以下行一样简单:

import * as moment from 'moment';

我倾向于将这种语法用于大多数具有对象的库,例如shortidlinqlodash

其他库与declare var 语句一起工作得更好。例如,我发现 jQuery 以这种方式工作得更好。

declare var $

自动完成

如果您正在寻找自动完成功能,您需要为库加载一个 .d.ts 文件。 moment 的 npm 包自带一个,但有些库需要为此安装另一个 npm 包(例如@types/lodash@types/jquery)。

Visual Studio 自动完成依赖于 .d.ts 文件来识别类型。配置该功能的文档位于here,或许可以进行配置(见底部附近的注释)。

【讨论】:

  • 谢谢@theMayor;我使用&lt;script&gt; 标记来导入以简化问题,因为我们实际上正在做的是用于全局变量的 webpack-chunks,以便在浏览器主事件循环以及 web 和服务工作者中重用缓存。这些库有效地显示为全局变量,就像脚本标记一样。所有这些都与打字稿无关(我们包括 50 多个 JS 库,总计数十 MB,因此缓存/分块对性能很重要);关键是我们不想为每个工人导入应用程序中每个库的副本,这就是import * as moment from 'moment' 所做的?
  • @BrianM.Hunt - 我不确定我是否理解您要完成的工作 - webpack 不会自动执行此操作吗?在任何情况下,您都可能放弃了 VS Code 可能必须提供的任何类型检查,因此,首先产生了 Typescript 的大部分(如果不是全部)好处。
  • 类型检查不需要包含,就像在 C/C++ 中 .h 文件可以提供外部库的类型一样。
  • 但是,如果你错过了什么?无论如何,应该将问题改写为“如何在不导入库的情况下获得智能感知?”因为从一开始就会清楚得多。简短的研究表明这是可能的。
  • 是的,我的意思是,这是对 JavaScript 的一种古老的挫败感。似乎确实将自己附加到全局范围的东西是“老派”,因此,也许将打字稿放在一起的人们没有太多考虑?
猜你喜欢
  • 2018-05-10
  • 2017-11-21
  • 2021-06-29
  • 2012-10-06
  • 1970-01-01
  • 2018-01-05
  • 2023-01-30
  • 2021-10-30
相关资源
最近更新 更多