What if TypeScript libraries published just .ts sources to npm instead of .js and .d.ts files? This might already be tempting for Bun-only libraries, but how will that impact users? This is easy to answer by experimenting on existing libraries that ship .js, .d.ts, and .ts files.
RxJS ships .js and .d.ts files, but also .ts files for debugability purposes. By tweaking its package.json "exports", we can compare tsc performance on this file with imports resolving to .d.ts files vs .ts source files:
import {} from "rxjs";
import {} from "rxjs/ajax";
import {} from "rxjs/fetch";
import {} from "rxjs/operators";
import {} from "rxjs/testing";
import {} from "rxjs/webSocket";| .d.ts | .ts | |
|---|---|---|
| Files | 268 | 317 |
| LOC | 49k | 62k |
| Instantiations ❗ | 11k | 46k |
| Memory | 92 kB | 118 kB |
| Parse time | .76 s | .91 s |
| Check time ❗ | 1.48 s | 3.02 s |
| Total time ❗ | 2.58 s | 4.43 s |
Obviously .ts files look really bad here, which is what I was expecting. I did expect the memory/parse difference to be more dramatic, and the check difference to be less, though! RxJS already uses isolatedDeclarations-compliant style, so this is likely the best case check penalty.
Do not skip .d.ts emit if you care about your users’ DX, even in a world where all your users can consume TS directly.
- typescript 5.2.2
- Node.js 14.21.3 (working on something old recently)
- tsconfig:
noEmit,"module": "nodenext" - test file:
index.ts(CommonJS format) - Apple M2, 16 GB RAM
- stats from
tsc --extendedDiagnostics - times average of three runs
Modifications to node_modules/rxjs/package.json took the form
"exports": {
".": {
- "types": "./dist/types/index.d.ts",
+ "types": "./src/index.ts",
"node": "./dist/cjs/index.js",
"require": "./dist/cjs/index.js",
"es2015": "./dist/esm/index.js",
"default": "./dist/esm5/index.js"
},for each "exports" subpath (except "./internal/*" which was not directly imported from the test file).
Yes, performance isn’t the only potential problem.