Skip to content
tezvyn:
Menu

How do you write a minimal dom-utils.d.ts for a JS function?

Source: typescriptlang.orgEasyHow cards are made

Tests bridging untyped JavaScript into TypeScript via ambient module declarations. A strong answer declares a module matching the file path and exports the function with a typed signature. Red flag: suggesting rename to .ts or using any.

What's really being asked

This question tests whether you can bridge untyped JavaScript into TypeScript using ambient module declarations. The interviewer wants to see if you understand that TypeScript can consume plain JS files without rewriting them, and whether you know the minimal syntax to make the compiler aware of a function signature. It also checks if you recognize the relationship between the import path and the module declaration string.

The full answer

A good answer hits four things in order. First, mention that you create a file named dom-utils.d.ts in the same directory as dom-utils.js. Second, declare a module block whose string literal matches exactly how the consumer imports it, such as declare module "dom-utils" if imported by name, or declare module "./dom-utils" if imported by relative path. Third, inside the module block, export the function with an explicit signature, for example export function focusFirstInput(): void. Fourth, note that the .d.ts file must be included in the TypeScript project, either by being picked up via include in tsconfig.json or by being referenced, so the compiler actually sees the declarations.

The mistakes people make

Common wrong answers include suggesting you rename dom-utils.js to .ts, which misses the point of the exercise. Another red flag is using declare global and attaching focusFirstInput to the global scope, which is unnecessary and pollutes the global namespace. Some candidates write the function body inside the .d.ts file, forgetting that declaration files contain only type information and no runtime code. A frequent mistake is omitting the export keyword inside the module declaration, which makes the function unreachable from an import statement. Finally, typing the function as any or using a blanket declare module "*" shows a lack of precision and defeats the purpose of TypeScript.

What usually comes next

The interviewer might ask how to handle default exports versus named exports in a .d.ts file. They could ask what happens if the JS file uses CommonJS module.exports instead of ES modules, which would require an export = syntax. Another follow-up is how to auto-generate declaration files from JavaScript using allowJs and declaration emit. They might also ask how to type a function that accepts an optional callback or complex DOM types like HTMLElement.

A concrete example

If dom-utils.js lives in src/utils and is imported as import { focusFirstInput } from "./utils/dom-utils", then the minimal src/utils/dom-utils.d.ts should read: declare module "./utils/dom-utils" { export function focusFirstInput(): void; }. If the project uses path mapping or a bare specifier, the module string must match the import string exactly. For a function that actually takes an optional root element, the signature could be export function focusFirstInput(root?: HTMLElement | null): void.

Interview question

You are adding TypeScript types for an existing dom-utils.js file imported via import { focusFirstInput } from './utils/dom-utils'. Which dom-utils.d.ts content uses the correct minimal ambient declaration?

  • a.declare module "./utils/dom-utils" { function focusFirstInput(): void; }
  • b.declare global { function focusFirstInput(): void; }
  • c.declare module "./utils/dom-utils" { export function focusFirstInput() { document.querySelector("input").focus(); } }
  • d.declare module "./utils/dom-utils" { export function focusFirstInput(): void; }Correct
Why?

The correct answer declares a module whose string matches the import path and exports the function with a type signature so it is importable. Option A is a common trap because it omits the export keyword, which makes the function unreachable from an import statement.

Just read this? Test yourself on what you have been reading.

Read the original → typescriptlang.org

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on typescript — each one lists the topics its interview covers.

See open roles