Here's how I usually set up vanilla javascript projects these days to enable typescript compiler jsdoc linting via jsconfig.json with checkJs: true.
First you need a jsconfig.json with at least "checkJs": true.
TypeScript as a dev dependency npm i -D typescript. Not needed for build
since it's vanilla javascript.
You might want to disable many of these if you are adding this to an existing codebase.
Then you'll start seeing TypeScript warnings in your codebase. Here are some strategies for handling those warnings in vanilla javascript.
types.d.ts
type State = "foo" | "bar" | "baz";Types defined there are automatically available in all js files in the project, no need to import any types.
thing.js
/** @type {State} */
let state = "foo";const element =
/** @type {HTMLCanvasElement} */ document.querySelector("#canvas");Here's where the syntax might get a little ugly. But in the end it's not that different from some workarounds you would sometimes need in regular TypeScript.
JSDoc TypeScript Reference - Casting
Having a unit test suite for Node.js can be useful even if you are just targeting the browser and loading normal js-files from html-files. Here's how you can unit-test javascript-files without adding another dependency.
Node.js Test Runner Documentation
-
Do
npm initto create apackage.json- Would recommend having
privatetrueunless you are going to publish to npm - Set
"type": "module"to enable normal.jsfiles to be ecmascript modules with import/export
{ "private": true, "type": "module" } - Would recommend having
-
Extract what you want to test into a separate file
thing.jsif possible -
Create for example a
thing.test.jstest fileimport test, { describe } from 'node:test' import assert from 'node:assert' import thing from './thing.js` describe('thing', () => { test('works', () => { assert.deepEqual(thing(), { foo: 'bar' }) }) })
-
Run
node --test -
Try watch-mode
node --test --watch -
Try running an individual file
node --test thing.test.js
{ "compilerOptions": { "target": "es2021", // Latest major browser support "module": "Node16", // Use Node16 module syntax "moduleResolution": "node16", "checkJs": true, // Enable type-checking for JavaScript files "strict": true, // Enforce strict type-checking "noImplicitAny": false, // Disallow implicit 'any' types "noUnusedLocals": true, // Error on unused local variables "noUnusedParameters": true, // Error on unused function parameters "noImplicitReturns": true, // Ensure all code paths in a function return a value "noFallthroughCasesInSwitch": true, // Prevent fallthrough errors in switch statements "allowSyntheticDefaultImports": true, // For compatibility with some module systems "noEmit": true, // Prevents any output files "lib": ["es2021", "dom", "dom.iterable"], // Include DOM typings for browser environments }, }