Add custom typings file in a JavaScript VSCode project

百般思念 提交于 2019-12-29 03:37:28

问题


Problem

I am working on JavaScript project using VSCode. I am using the UMD design pattern and vscode intellisense cannot recognize the exports of a module from another file. I added all the declarations in a file called globals.d.ts. Unfortunately I couldn't find a way to load the globals.d.ts declarations from my JavaScript files.

Example Module declaration

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

Example JavaScript File

(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;
}));

What I tried

I tried using typings install "globals.d.ts" which created the typings folder, typings.json etc. This was only working after opening the typings file in VSCode then closing and reopening the app. That only worked while I kept the typings file open. This is not a very convenient way to add my interface declarations.

About VSCode (8 months ago)

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

About VSCode (Now)

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

There is no change in behavior.


回答1:


Plain Node.JS solution

Create next files (names should be the same):

lib.js 
lib.d.ts

Inside lib.js write some code, lets say this one:

function whenDo(params) {
    return params;
}

module.exports = whenDo;

Inside lib.d.ts write this:

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

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

export = wd;

Then, create somewhere file to consume newly created function and put this code:

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

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

And magic is here, all worked just fine.

Code was stolen from here https://github.com/Drag13/WhenDo/blob/master/src/index.d.ts




回答2:


ES6 import syntax solution for those who are using babel

Create next files (names should be the same):

lib.js 
lib.d.ts

Inside lib.js write some code, lets say this one:

export const testMethod = (name, params) => params && params.age ? `hello ${name} with age: ${params.age}` : `hello ${name}`;
export const myConst = {
     name: 'test',
     age: 5
 };

Inside lib.d.ts write this:

declare namespace MyModule {
    interface IParams { age: number; }

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

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

Then, create somewhere file to consume newly created function and put this code:

import { testMethod } from "./lib/lib";

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

Now, intellisense should works fine for params and result.

But. This approach requires you to use babel to friend node.js and imports. If you will try to change code from import style to require style you still will see types and arguments, but intelisence will fail.

Simple babel check:

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

My VsCode version is 1.24.1




回答3:


Acknowledgment

This answer was mostly copied/inspired by Vitalii's answer, but since it had to be modified a bit, to work with my project, I am also adding this answer.

Solution

On top of each file where I use external code, I added:

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

Undefined is the shortest and simplest way (that I thought of) of having a constant false value without triggering eslint or jshint. This ensures that the code will never be run, while still "requiring" the jsdoc.

I used var instead of let or const since it will not stay in the if scope, but rather the global file scope.

This will actually declare the variables inside the {} (as undefined), but typeof undeclared and typeof undefined are both "undefined", thus there is no difference in the code.

By having all the declarations in one file, I can get all the namespaces by destructuring one require statement in one line. But keep in mind, that in order for this to work, you need to be using export and not declare in your typings file.

Problems with Solution

I cannot view the interfaces in globals.d.ts from JavaScript files.

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

I have temporarily fixed this problem by renaming the namespace with the interfaces to Interfaces (also fixed all the references in globals.d.ts) and created another Namespace with constants that implement the interfaces, like so:

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

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

I also had trouble using the namespaces from globals.d.ts in JavaScript comments. To solve this problem I added typeof infront of the type, like so: /** @param {typeof Namespace.Interface} */

Update

I have now found a way to export interfaces from .d.ts files to .js files, you can find the answer here.



来源:https://stackoverflow.com/questions/46678663/add-custom-typings-file-in-a-javascript-vscode-project

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!