Typescript via jsdocs
Steven Chetwynd
350 Words … ⏲ Reading Time: 1 Minute, 35 Seconds
2025-02-28 13:22 +0000
Generic Classes
To create a generic class we can use the @template
tag above the class, and reuse the template name in the class methods and properties:
/**
* @template T
*/
class MyClass {
/** @type {t} */
#prop;
/**
* @param {T} value
*/
constructor(value) {
this.#prop = value;
}
/**
* @returns {T}
*/
getValue() {
return this.#prop;
}
}
/** @type {MyClass<string>} */
const foo = new MyClass("test");
If the generic needs to extend another type we can use @template {OtherType} T
.
Classes implement
To make a class implement an interface, I like to declare the interface in a .d.ts
file and import it into my file. But it is not possible to use import directly in the @implements
tag, we need to use a @typedef
first.
// types.d.ts
export interface MyInterface {
greet: () => string;
}
/**
* @typedef {import("./types").MyInterface
* @implements {MyInterface}
*/
class EsperantoGreeter {
/**
* @returns {string}
*/
greet() {
return "Saluton";
}
}
Overloading functions
It is possible to use the @overload
tag to list a series of different inputs to a single function/method and the results of the each different input.
I recently found this useful when passing an object or array of objects into a function which would return either an object or an array of objects depending on what was passed.
export interface my_obj {
my_value: string;
my_other_value: string;
}
export interface MyObj {
myValue: string;
myOtherValue: string;
}
/**
* @overload
* @param {import("./types").my_obj} obj
* @returns {import("./types").MyObj}
*/
/**
* @overload
* @param {import("./types").my_obj[]} obj
* @returns {import("./types").MyObj[]}
*/
/**
* @param {import("./types").my_obj | import("./types").my_obj[]} obj
* @returns {import("./types").MyObj | import("./types").MyObj[]}
*/
function myFunction(obj) {
const transformObj = (obj) => ({
myValue: obj.my_value,
myOtherValue: obj.my_other_value
});
if (Array.isArray(obj)) {
return obj.map((el) => transformObj(el));
}
return transformObj(obj);
}
I have only come across this whilst introducing types to old code, and going forward I would choose not to write code like this because it can cause the JavaScript engine to bail out on any optimisation it has made. (A crash course in just-in-time (JIT) compilers)