Skip to the solution
HardFrontend12 min read

How do you author library types that pass isolatedDeclarations for oxc / tsdown builds?

499 views

The problem

Question presented to candidate: "Your team wants to move a TypeScript library from tsc to tsdown so declaration files are generated by oxc. What changes in how you write the code, and how do you make sure the published types stay the same?"

What a strong answer should cover:

  • The switch: tsdown generates declarations through rolldown-plugin-dts, which picks its oxc generator when compilerOptions.isolatedDeclarations is enabled (tsc otherwise); oxc copies types from syntax and never runs a checker
  • The authoring rules: explicit return types on exported functions and methods, annotations on exported variables set from calls or new, typed parameters with non-literal defaults, named default exports; literals, literal objects and as const stay unannotated
  • Writing the same type inference produced, not a wider one: Record<string, string> instead of as const silently loses keys, any passes and ruins the API; this for fluent methods, generics spelled out
  • The traps found by running both tools: satisfies is rejected by tsc but accepted by oxc, typeof a local pulls the local into the .d.ts, spreads and computed keys need explicit types
  • The safety net: keep tsc --noEmit with isolatedDeclarations as the CI gate, diff the emitted .d.ts before and after, and check the package with attw

Clarifying questions expected:

  • Is this a library that publishes .d.ts files, or an app (where the flag rarely pays off)?
  • How big is the public API, and is a monorepo build waiting on declaration emit?

Code / implementation expected: Yes β€” rewrite a few failing exports so they pass, and show that the public types are unchanged.

  • isolatedDeclarations
  • publishing

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

12 min read Β· 11 sections

Run the code

Edit the code and run it here. Each console line with an expected value becomes a test.

TypeScriptAnnotating without changing the public types
TypeScriptA library entry that passes isolatedDeclarations
// src/index.ts of a library built by tsdown / rolldown-plugin-dts with the oxc generator.
// Passes tsc 5.9.3 --isolatedDeclarations; oxc emits the same .d.ts (see the answer).
const routes = { home: "/", about: "/about" } as const;
export const ROUTES: typeof routes = routes;
export type RouteName = keyof typeof ROUTES;

const defaults = { retries: 3, verbose: false };
export type Defaults = typeof defaults;
export const DEFAULTS: Defaults = defaults;

export function wrap<T>(x: T): T[] { return [x]; }

export function parse(input: string): number;
export function parse(input: number): string;
export function parse(input: string | number): number | string {
  return typeof input === "string" ? Number(input) : String(input);
}

export class Store {
  #items: string[] = [];
  constructor(public readonly name: string, private limit = 10) {}
  get size(): number { return this.#items.length; }
  add(item: string): this { this.#items.push(item); return this; }
  static create = (name: string): Store => new Store(name);
}

export const handlers = {
  onSave: (id: string): void => {},
  onLoad(id: string): Promise<string> { return Promise.resolve(id); },
};

export enum Level { Low = 1, High = 2 }
export const VERSION = "1.0.0";
export let counter = 0;

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 74 of 81 in TypeScript

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

Up nextHard

What is module augmentation?

Continue