How to Get Full TypeScript IntelliSense in Plain JavaScript with VSCode
This tutorial explains how to bring TypeScript‑style type checking and autocomplete into regular JavaScript files using VSCode, JSDoc comments, and declaration files, allowing developers to enjoy static‑type benefits without converting the whole project to .ts files.
Preface
Many TypeScript fans sigh that they want to use TS but are forced to write plain JavaScript. This article shows that you can work fluently with TypeScript features inside JavaScript, and your manager won’t complain.
Written Up Front
Previous article: TS Advocacy Guide [1]
After reading the previous guide, many commenters said, “TS is great, but our boss doesn’t care.” This sequel explains the results of my long‑term experiments with using TypeScript inside JavaScript.
If you already know TS, the article will be smooth; if not, you can still follow along, and if you dislike TS, just treat it as a fun read.
The article targets the latest VSCode (v1.41.0). Other IDEs may behave differently.
WebStorm also supports these features, but because it has its own intelligent engine, it is not discussed here.
What? You still use Notepad?
How It Works
TypeScript Inside VSCode
TypeScript was released by Microsoft in 2012 but did not gain much attention in China before VSCode existed. Some developers recognized its potential to fix JavaScript’s weaknesses and started using it, especially those with backend backgrounds who preferred static typing and IDEs like Visual Studio or Eclipse that already supported TS.
When VSCode appeared, it became a lightweight IDE for front‑end developers, and TS adoption surged. Even when you write plain JavaScript, VSCode can provide TypeScript‑powered suggestions automatically.
TypeScript Inside JavaScript
Ever wondered why typing
document.in a JS file triggers a popup of all DOM methods? That’s because VSCode bundles the TypeScript library, which includes declaration files such as
lib.dom.d.tsthat describe DOM APIs.
The file lists many familiar method names, providing DOM‑related IntelliSense for plain JavaScript.
In JavaScript, the scope of TypeScript usage is actually broader than you might think.
Elegant Declaration Files
Let’s talk about the
.d.tsdeclaration files that give you type hints.
Built‑in Declaration Files
VSCode ships a
node_modulesfolder that contains the TypeScript package and a set of basic
.d.tsfiles. To enable newer ECMAScript features, create a
jsconfig.jsonin the project root:
<code>{
"compilerOptions": {
"lib": ["dom", "esnext"]
}
}
</code>Now you can enjoy ES2020 syntax suggestions.
Package‑Provided Declaration Files
Some packages ship their own declaration files. For example,
@types/nodeprovides Node.js APIs. Install it with:
<code>npm i @types/node -D
</code>Now you get intelligent hints for Node.js globals.
Global Variables
Front‑end teams often attach utilities to
window. By writing a declaration file you can make those globals typed:
<code>interface ILib {
/** Get current environment */
getEnv: string;
/** Image methods */
img: {
formatImg: (a: string, b: string) => string;
};
/** URL methods */
url: {
formatUrl: (a: string) => string;
};
}
declare var XXCompanyLib: ILib;
</code>Magic Comments – JSDoc
Standard JavaScript comments (
//and
/* */) are familiar, but JSDoc (
/** */) can embed type information directly in JS files.
<code>/**
* Method: foo
* @param {string} name
*/
function foo(name) {
console.log(name);
}
</code>What JSDoc Solves
When a function’s parameters lack type annotations, the IDE treats them as
any, causing loss of type safety. Adding JSDoc @param tags tells VSCode the expected types, and the return type can be inferred.
<code>function foo(a, b) {
console.log(a);
console.log(b);
return a; // return any
}
var bar = foo(1, 2); // bar is any
</code>After adding JSDoc:
<code>/**
* @param {string} name
* @returns {string}
*/
function foo(name) {
return name;
}
var bar = foo('test'); // bar is string
</code>Advanced Tags
Beyond @param and @return, JSDoc supports @typedef and @property to describe complex objects.
<code>/**
* @typedef {Object} IAjaxOptions
* @property {boolean} [jsonp]
* @property {boolean} [async]
* @property {'GET'|'POST'} [methods]
* @property {function(options:any):void} [success]
*/
/**
* @param {string} url
* @param {IAjaxOptions} [options]
*/
function ajaxNew(url, options) {}
</code>Don’t Overuse
Using JSDoc everywhere can become noisy and hard to maintain. It’s best for frequently used APIs or shared utilities.
Manual annotation can be time‑consuming.
Inconsistent documentation leads to confusion.
Incorrect @type can hide real bugs.
VSCode’s JSDoc support is still limited for complex types.
When possible, migrate the codebase to real
.tsfiles for full type safety.
Practical Recommendations
Fix the Root Cause First
VSCode can infer many types automatically if the code is written clearly. For example, instead of adding a property after object creation, define it upfront:
<code>var foo = { a: 1, b: 2 };
// IDE now knows foo.a and foo.b
</code>Use typeof in JSDoc
When you want a function to accept an object with the same shape as an existing variable, use
{@type {typeof foo}}:
<code>/** @param {typeof foo} obj */
function bar(obj) {
obj.a; // jumps to foo.a definition
}
</code>Enable // @ts-check
Adding
// @ts-checkat the top of a JS file makes VSCode treat the file as if it were TypeScript, reporting type errors.
Annotate Frequently Used Objects
For global utilities like
zepto, create a typedef that re‑exports the type:
<code>/** @typedef {typeof $} ZeptoStatic */
/** @type {ZeptoStatic} */
var $ = require('zepto');
</code>Using TypeScript in Vue
Vue already ships
vue.d.ts. By importing the type of the component options you can get full IntelliSense without changing the file extension.
<code>/** @type {import('vue').ComponentOptions} */
const options = {
name: 'app',
data() { return { shareDialog: false }; },
methods: {
click() { console.log(123); }
}
};
</code>Advanced Practices
TS in JS with JSDoc – Merging Objects
Use @returns to describe the combined type of two objects:
<code>/**
* Merge two scopes
* @returns {{...typeof args & typeof fn}}
*/
function someMergeFn(args, fn) {
// ...implementation
}
const newObj = someMergeFn(args, fn);
newObj.a; // jumps to args.a
newObj.bar; // jumps to fn.bar
</code>Re‑exporting Types from Other Files
When a module returns an object without a proper export, you can annotate the import:
<code>/** @type {import('./otherService')} */
var newObj = someRequireFn('./otherService');
newObj.a; // jumps to otherService.js args.a
newObj.bar; // jumps to otherService.js fn.bar
</code>Combining Declaration Files and JSDoc
Create a custom
.d.tsthat describes a complex shape, then reference it from JSDoc:
<code>// InterfaceJs.d.ts
export interface INewObj {
a: number;
b: number;
foo(): void;
bar(): void;
}
/** @type {import('./InterfaceJs').INewObj} */
var newObj = someRequireFn('./otherService');
newObj.a; // jumps to INewObj definition
</code>Conclusion
There are two main ways to bring TypeScript capabilities into JavaScript:
Use declaration (
.d.ts) files.
Write JSDoc comments.
Both can be combined for more complex scenarios. Apply them to shared components, global variables, and frequently used functions to get reliable IntelliSense without a full migration to TypeScript.
How to Apply
Write declaration files for public components and globals.
Add JSDoc to custom functions and keep them tidy.
Use
@typeto give explicit types to ambiguous variables.
Precautions
Don’t overuse JSDoc; it can become a maintenance burden.
Prefer “jump‑to‑definition” over artificial type casts.
If you want to try the demos locally, clone the repository linked below and open the files in VSCode.
References
[1]TS Advocacy Guide – https://juejin.im/post/5d8efeace51d45782b0c1bd6
[2]Same as above.
[3]Demo repository – https://github.com/Lienviws/TS_in_JS_DEMO
[4]Module resolution – https://www.tslang.cn/docs/handbook/module-resolution.html
[5]Type search – https://microsoft.github.io/TypeSearch/
[6]DefinitelyTyped – https://github.com/DefinitelyTyped/DefinitelyTyped/
[7]Declaration files guide – https://ts.xcatliu.com/basics/declaration-files
[8]JSDoc @param – https://jsdoc.app/tags-param.html
[9]JSDoc @type – https://jsdoc.app/tags-type.html
[10]JSDoc @typedef – https://jsdoc.app/tags-typedef.html
[11]JSDoc homepage – https://jsdoc.app/index.html
[12]Demo repo – https://github.com/Lienviws/TS_in_JS_DEMO
[13]Official site – https://wecteam.io/
WecTeam
WecTeam (维C团) is the front‑end technology team of JD.com’s Jingxi business unit, focusing on front‑end engineering, web performance optimization, mini‑program and app development, serverless, multi‑platform reuse, and visual building.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.