I like scripting in JS, but there are also many benefits in strong typing. I have not decided how far I will got with strict, but limit is when it becomes difficult, or in my opinion is more hassle than it is worth.
Idea is to write JS 99%, and write TypeScript only for defining interfaces and types when there is no JS Class,
Use the VSCode provide error reporting in the editor and hints (intelisense).
Minimal tsconfig
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"target": "ESNext",
"outDir": "build",
"moduleResolution": "node16"
},
"exclude": ["node_modules", "build_dev", "build", "dist"]
}
At this moment *.jsx
files have hints for method parameters, but not *.js
. To avoid this issue open :
File->Preferences->Settings
and search assoc
to get to File associations
and add
*.js
->javascriptreact
If using JSX
and not React
then you need a copy of tsconfig.json
called for example tsconfig-custom.json
because you need to have compilerOptions.jsx:"preserve"
for tsc
to not complain and that will then make a problem with esbuild if you use compilerOptions.jsx:"automatic"
there
JSDoc will be used to define types
It is more compact to write type definitions for data objects in TypeScript than in JSDoc so I write them in a file _types.ts
export interface LinePoint {
pos: Array<number>
con: ConnectorData
listen: Array<Function>
align: string
}
If you need to attach custom properties to HTML elements and use compiler help you need to define an interface
export interface HTMLConnector extends HTMLElement {
ncData: ConnectorData
}
If you use built-in browser function that returns Element
then you need to cast the result for compiler to know it. Casting is done by in-lining @type
JSDoc comment and also adding ()
parenthesis around the expression.
let target = /** @type {HTMLConnector} */ (document.elementFromPoint(x, y))
let ncData = target.ncData
If type is defined in separate file you need to import the definition in JSDoc import('./_types.js').HTMLConnector
.
let target = /** @type {import('./_types.js').HTMLConnector} */ (document.elementFromPoint(x, y))
To avoid this noise in the code where the type is used, you can declare the type in the beginning of your file. Later when you want to use it you just reference it by Name.
/**
* @typedef {import('./_types.js').HTMLConnector} HTMLConnector
*/
.....
let target = /** @type {HTMLConnector} */ (document.elementFromPoint(x, y))