Recently, I started writing some TypeScript definition files from my team. These definition files addressed the problem that some old common packages writing in JavaScript are missing TypeScript support. Meanwhile, our team is migrating projects from JavaScript to TypeScript incrementally.
TypeScript definition file (.d.ts) is like an add-on for JavaScript files that can provide TypeScript definitions without changing the original file. We call declarations that don’t define an implementation “ambient”[1]. To write an ambient module from an existing module, use declare modul
e keyword. For example.
declare module "lodash" {
export function uniq<T>(data: T[]) => T[];
}
When writing an ambient module, there are serveral points you need to take care of.
- Test it in different IDEs.
It’s strange but I found VSCode and WebStorm sometimes have different behaviors treating the same definition file. Test from both IDEs to make sure your definition works.
- Don’t use
import
outside the module
You can’t use import
outside of the declare module
block. This will cause TypeScript treating the file as a normal module rather than an ambient module[2]. The right way to reference types from other modules is
declare module "lodash" {
import { Request, Response } from "express";
export interface CustomRequest extends Request {
// ....
}
}
- Add some generics for uncertain return values
When you are adding type definitions for a method that do not have a certain data structure for return values, add a generic parameter to let user to control it. For example.
export const getQueryFormURL<T = Record<string, string>> = (url: string) => T;
References
- https://www.typescriptlang.org/docs/handbook/modules.html#working-with-other-javascript-libraries
- https://stackoverflow.com/questions/39040108/import-class-in-definition-file-d-ts