Advanced TypeScript for Harness Builders

0e. Type Narrowing (Runtime)

TypeScript's killer feature: it tracks runtime checks and narrows types automatically.

TypeScript tracks runtime checks and narrows types automatically. This is its killer feature.

typeof checks:

File: packages/ai/src/env-api-keys.ts L14

if (typeof process !== "undefined" && (process.versions?.node || process.versions?.bun)) {
  // Inside here, TypeScript knows `process` exists
}

instanceof checks:

File: packages/mom/src/log.ts L167

err instanceof Error ? err.message : String(err);

After instanceof Error, TypeScript knows err has .message.

Truthiness narrowing:

File: packages/mom/src/sandbox.ts L36-38

const result = await execSimple("docker", ["inspect", "-f", "...", config.container]);
if (result.trim() !== "true") {
  // TypeScript still knows result is string here
  console.error(`Error: Container '${config.container}' is not running.`);
}

Optional chaining (?.) narrows to undefined:

File: packages/ai/src/env-api-keys.ts L14

process.versions?.node || process.versions?.bun;

?. returns undefined if the left side is null/undefined. Combined with ||, this is a safe way to check nested properties.

These are all JavaScript features, but TypeScript is the one that tracks them for type safety. In JS, typeof is just a runtime check. In TS, it also changes what the compiler thinks the type is inside the if block.


Open this chapter inside the full course