Loading lesson path
Concept visual
Start at both ends
JSDoc with TypeScript allows you to add type checking to JavaScript files without converting them to.ts. This is perfect for gradual migration or when you want type safety in JavaScript projects.
To enable TypeScript checking in JavaScript files, you need to: Create a tsconfig.json file (if you don't have one)
Formula
// @ts - check in individual filesFormula
// @ts - check/** * Adds two numbers.
* @param {number} a
* @param {number} b
* @returns {number}*/
function add(a, b) {
return a + b;
}Formula
// @ts - check/** * @param person */
function greet(person) {
return `Hello, ${person.firstName} ${person.lastName}`;
}
greet({ firstName: 'John', lastName: 'Doe' }); // OK
greet({ firstName: 'Jane' }); // Error: Property 'lastName' is missingUsing @typedef for Complex Types
Formula
// @ts - check/**
* @typedef {Object} User
* @property {number} id - The user ID
* @property {string} username - The username
* @property {string} [email] - Optional email address
* @property {('admin'|'user'|'guest')} role - User role
* @property {() => string} getFullName - Method that returns full name*/
/** @type {User} */
const currentUser = {
id: 1, username: 'johndoe', role: 'admin', getFullName() {
return 'John Doe';
}
};
// TypeScript will provide autocomplete for User properties console.log(currentUser.role);Formula
// @ts - check/ @typedef Point */ /
* @typedef {Point & { z: number }} Point3D*/
/** @type {Point3D} */
const point3d = { x: 1, y: 2, z: 3 };
// @ts-expect-error - missing z property const point2d = { x: 1, y: 2 };Formula
// @ts - check/** * Calculates the area of a rectangle
* @param {number} width - The width of the rectangle
* @param {number} height - The height of the rectangle
* @returns {number} The calculated area*/
function calculateArea(width, height) {
return width * height;
}
// TypeScript knows the parameter and return types const area = calculateArea(10, 20);Formula
// @ts - check/** * @callback StringProcessor
* @param {string} input
* @returns {string}*/ /**
* @type {StringProcessor}*/
const toUpperCase = (str) => str.toUpperCase();/**
* @param {string[]} strings
* @param {StringProcessor} processor
* @returns {string[]}*/
function processStrings(strings, processor) {
return strings.map(processor);
}
const result = processStrings(['hello', 'world'], toUpperCase);
// result will be ['HELLO', 'WORLD']Formula
// @ts - check/** * @overload
* @param {string} a
* @param {string} b
* @returns {string}*/ /** * @overload
* @param {number} a
* @param {number} b
* @returns {number}*/ /**
* @param {string | number} a
* @param {string | number} b
* @returns {string | number}*/
function add(a, b) {
if (typeof a === 'string' || typeof b === 'string') {
return String(a) + String(b);
}
return a + b;
}
const strResult = add('Hello, ', 'World!'); // string const numResult = add(10, 20); // numberFormula
// @ts - check/** @typedef Person */
/** @typedef {Person & { employeeId: string }} Employee */
/** @typedef {Person | { guestId: string, visitDate: Date }} Visitor */
/** @type {Employee} */
const employee = {
name: 'Alice', age: 30, employeeId: 'E123'
};
/** @type {Visitor} */
const guest = {
guestId: 'G456', visitDate: new Date()
};/**
* @param {Visitor} visitor
* @returns {string}*/
function getVisitorId(visitor) {
if ('guestId' in visitor) {
return visitor.guestId; // TypeScript knows this is a guest
}
return visitor.name; // TypeScript knows this is a Person
}Formula
// @ts - check/** * @template T
* @typedef {[K in keyof T]: T[K] extends Function ? K : never}[keyof T] MethodNames*/ /** * @template T
* @typedef {{
* [K in keyof T as `get${'<' }Capitalize<string & K>{'>'}`]: () => T[K]
* }} Getters*/
/** @type {Getters<{ name: string, age: number }> } */
const userGetters = {
getName: () => 'John', getAge: () => 30
};
// TypeScript enforces the return types const name = userGetters.getName(); // string const age = userGetters.getAge(); // numberFormula
// @ts - check// Importing types from TypeScript files
/** @typedef {import('./types').User} User */// Importing types from node_modules
/** @typedef {import('express').Request} ExpressRequest */// Importing with renaming
/** @typedef {import('./api').default as ApiClient} ApiClient */Create a types.d.ts file in your project:
// types.d.ts declare module 'my-module' {
export interface Config {
apiKey: string;
timeout?: number;
retries?: number;
}
export function initialize(config: Config): void;
export function fetchData<T = any>(url: string): Promise<T>;
}Then use it in your JavaScript files:
Formula
// @ts - check/** @type {import('my-module').Config} */
const config = {
apiKey: '12345', timeout: 5000
};
// TypeScript will provide autocomplete and type checking import { initialize } from 'my-module';
initialize(config);Follow these best practices when using JSDoc with TypeScript:
Formula
// @ts - check at the top of files where you want type checking@typedef for complex types that are used in multiple places
@template for generic functions and types Create declaration files (.d.ts
Formula
) for third - party libraries without typesFormula
@ts - expect - error instead of
@ts - ignore when you expect an errorWatch out for these common issues: