在JavaScript的VSCode项目中添加自定义的类型文件

28

问题

我正在使用VSCode进行JavaScript项目开发。我使用UMD设计模式,但是vscode智能感知无法识别来自另一个文件的模块的导出。我在一个名为globals.d.ts的文件中添加了所有声明。不幸的是,我找不到一种方法从我的JavaScript文件中加载globals.d.ts声明。

示例模块声明

export namespace ModuleName {
    export interface Item {
        toString(): string;
        property: string;
        name: string;
    }
}

JavaScript文件示例

(function (global, factory) {
    "use strict";
    if (typeof ModuleName === "undefined" && typeof require === "function") global.ModuleName = require("./mymodule.js");
    if (typeof exports !== "undefined" && typeof module !== "undefined") factory(exports);
    else factory(global.OtherModule = global.OtherModule || {});
})(this, (function (exports) {
    "use strict";

    function myMethod() {

    }

    exports.myMethod = myMethod;
    return exports;
}));

我尝试的

我尝试使用typings install "globals.d.ts"命令,这创建了typings文件夹、typings.json等文件。但只有在打开VSCode编辑器并关闭再重新打开应用程序后才能正常工作。而且只有在保持typings文件处于打开状态时才能正常工作,这不是一种很方便的添加接口声明的方式。

关于VSCode(8个月前)

Version: 1.17.0
Shell: 1.7.7
Node: 7.9.0
Architecture: x64

关于 VSCode(现在)

Version: 1.24.1
Shell: 1.7.12
Node: 7.9.0
Architecture: x64

行为没有改变。


3
“typings已过时,你应该使用npm i @types/[模块名]来代替。” - PitaJ
2
如果你正在处理本地文件,那么你不应该使用它们。你应该在你的tsconfig文件中添加这些文件到“includes”中。 - PitaJ
如果您想在JavaScript项目中引用实际类型文件,我认为您需要添加一个tsconfig.json文件,并使用它来引用自定义类型。您还可以尝试使用“/// references”来引用类型文件。 - PitaJ
你尝试过使用JSDoc吗?你可以在你的对象(函数)上使用JSDocs的@type@param@returns来描述,智能感知将解析它们。 - christophersw
@nickzoum,VS Code 的最新版本为“Version 1.24.1 (1.24.1)”,请先升级后再分享您的反馈。 - Tarun Lalwani
3个回答

17

Node.JS简洁解决方案

创建以下文件(文件名应该相同):

lib.js 
lib.d.ts

在lib.js内编写一些代码,假设是这个:

function whenDo(params) {
    return params;
}

module.exports = whenDo;

在lib.d.ts中写入以下内容:

declare function wd(params: wd.Params): wd.Params;

declare namespace wd {
    interface Params {
        name: string;
    }
}

export = wd;

然后,创建一个文件来调用新创建的函数,并放入此代码:

const wd = require('./lib/lib');

const opt = wd({name:'drag13'});
console.log(opt.name);

在这里,神奇的事情发生了,一切都很顺利。 enter image description here

代码是从这里盗取的:https://github.com/Drag13/WhenDo/blob/master/dts/index.d.ts

这里描述的方法:here


我不确定为什么你需要在TypeScript中使用它(因为d.ts是一个TypeScript文件),但错误是什么? - Drag13
你能把你的d.ts文件放在某个地方吗?因为在我的NodeJs解决方案中,接口已经被呈现并且运行良好。 - Drag13
@nickzoum,我理解得对吗,你想为所有的代码保留一个单独的d.ts文件? - Drag13
@nickzoum 没错,因为我无法在 JavaScript 中声明类型(除非使用 jsdoc),所以我不需要直接使用接口。但是如果使用 jsDoc,我不知道如何链接它们。也许创建一个新问题是个好主意,因为我们已经远离原始问题了。 - Drag13

8

针对使用babel的ES6导入语法解决方案

创建以下文件(文件名应相同):

lib.js 
lib.d.ts

在lib.js文件中编写一些代码,假设是这个:
export const testMethod = (name, params) => params && params.age ? `hello ${name} with age: ${params.age}` : `hello ${name}`;
export const myConst = {
     name: 'test',
     age: 5
 };

在 lib.d.ts 中写入以下内容:
declare namespace MyModule {
    interface IParams { age: number; }

    function testMethod(name: string, params: IParams): string;

    const myConst: {
        name: string,
        age: number
    }
}
export = MyModule;

然后,创建一个文件来调用新创建的函数,并放入以下代码:
import { testMethod } from "./lib/lib";

const name = 'drag13';
const r = testMethod(name, { age: 5 });
console.log(r);

现在,参数和结果的智能提示应该可以正常工作了。

enter image description here

但是。这种方法需要你使用babel来友好地处理node.js和导入。如果你试图将代码从导入样式更改为要求样式,你仍然会看到类型和参数,但智能感知将失败。

简单的Babel检查:

npm i babel-preset-env babel-cli
./node_modules/.bin/babel-node index.js --presets env

我的 VsCode 版本是 1.24.1


2
如果你使用Babel,你可以在Node应用程序中使用导入。但据我所知,这是不可能的,对吧? - Drag13

5

致谢

本回答的大部分内容参考/借鉴了Vitalii的回答,但由于需要对其进行一定修改以适应我的项目,因此也添加了此回答。

解决方案

在我使用外部代码的每个文件的顶部,我都添加了以下代码:

if (undefined) var { -List of Namespaces used- } = require("./globals");

Undefined是我想到的最短、最简单的方法之一,可以声明一个常量假值而不触发eslint或jshint。这确保代码永远不会被运行,同时仍然“需要”jsdoc。

我使用var而不是let或const,因为它不会停留在if范围内,而是全局文件范围内。

实际上,这将在{}中声明变量(作为undefined),但未声明和undefined的typeof都是"undefined",因此在代码中没有区别。

通过将所有声明放在一个文件中,我可以通过一条require语句的解构来获取所有命名空间。

但是请记住,为了使其正常工作,您需要在typings文件中使用export而不是declare。

解决方案的问题

我无法从JavaScript文件中查看globals.d.ts中的接口。

export namespace Namespace {
    export interface Interface {
        property: string;
    }
}

我已经通过将接口命名空间重命名为Interfaces(并在globals.d.ts中修复了所有引用)暂时解决了这个问题,并创建了另一个常量命名空间来实现接口,如下所示:

export namespace Interfaces {
    export interface Interface {
        property: string;
    }
}

export namespace Namespace {
    export const Interface: Interfaces.Interface;
}

我也曾经遇到过在JavaScript注释中使用globals.d.ts中的命名空间时的困难。为了解决这个问题,我在类型前面加上typeof,像这样:/** @param {typeof 命名空间.接口} */

更新

我现在找到了一种将接口从.d.ts文件导出到.js文件的方法,你可以在这里找到答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接