Loading · TypeScript
Stack Innovations/ Services/ Custom Development/ TypeScript
03 / 08 · Custom Development
000Compiling TypeScript

TypeScript

Strict, well-typed software, engineered for the ten-year arc.

Start a build
The argument

A TypeScript codebase is just the bugs you catch before runtime.

Each schema · a contract. Each boundary · a guarantee. Each red build · a bug, not a ticket.
02 — Ecosystem

TypeScript,
and the right neighbours.

Language/01
TypeScript 5.x

Structural typing, narrowing, the satisfies operator and const type params. The type system, not a transpiler afterthought.

satisfiesNarrowingconst T
Compiler/02
tsc

Type-checking in CI on every PR; nothing merges with a red build.

--noEmitCI gate
Validation/03
Zod

Schemas that double as types — one source of truth for shape.

SchemaInfer
Linting/04
typescript-eslint

Type-aware lint rules that catch what tsc alone won't.

Type-awareRules
Formatting / Linting/05
Biome

A single fast, Rust-based tool replacing a chain of JS tooling.

RustFast
API contracts/06
tRPC

End-to-end type safety from server to client, no codegen step.

No codegenRPC
API contracts/07
ts-rest

Typed REST contracts when tRPC's coupling isn't the right fit.

RESTTyped
Testing/08
Vitest

Type-checked tests, the same runner across every project.

UnitIntegration
Bundling/09
tsdown

Zero-config bundling for shared packages and libraries, built on Rolldown.

ESMCJS
Monorepo/10
pnpm + Turborepo

Workspace-aware installs and cached, parallel builds across packages. One type-check, every package, every PR.

WorkspacesRemote cacheParallel
Utility types/11
type-fest

Battle-tested utility types for the patterns the standard library doesn't cover.

UtilitiesGenerics
03 — What we build

Three shapes,
one discipline.

01 — Platforms
Type-safe
platforms.

Full-stack TypeScript. One schema, shared end to end — server, client, and the database in between never disagree.

  • Shared types · client / servertRPC
  • Schema-first validationZod
  • Strict mode · repo-widetsc
  • CI type-check gatenoEmit
Schema Server Client Zod tRPC Inferred
02 — SDKs
SDKs &
shared packages.

Published npm packages with strict public APIs. The types are the documentation — autocomplete is the onboarding flow.

  • Public API surface · strictd.ts
  • Dual ESM / CJS outputtsdown
  • Semantic versioning · changesetsSemVer
  • Generic, reusable utility typestype-fest
export * from './types' d.ts strict public API esm/index.js cjs/index.js
03 — Monorepos
Monorepo
migrations.

Incremental JS→TS adoption, package by package. Strict mode rolled out file by file, never a big-bang rewrite.

  • Workspace boundaries mappedpnpm
  • any-audit · file by filetsc
  • Strict rollout · tracked %Coverage
  • Cached, parallel CI buildsTurborepo
pkg 1 pkg 8 pkg 16 strict: 100%
/ Phase 01 · Discover

Listen first.

Stakeholder interviews, support tickets, the existing codebase. We map the type discipline by mapping the work.

Discovery docTech auditRisk map
SCOPE ANY DATA TEAM RISK OUTCOME
packages/ apps/web — strict: false packages/api — strict: true packages/db — strict: true packages/ui — strict: false packages/shared-types vendor/* — untyped, @types shim
// schema.ts — single source of truth export const Order = z.object({ ... }) type Order = z.infer<typeof Order> router.input( Order) → one schema, both directions typed → no manual interface drift
// tsconfig.json { "compilerOptions": { "strict": false, "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true } } // rollout — 6 packages / 6 ████████████████████ 100% → rolled out file by file → never a single big-bang PR → red build blocks merge, always
w1 w6 w12 +100% type coverage
01
01
05
05 — Architecture

One type,
end to end.

// live · type Order — traced through the stack
Inferred Declared
Database Prisma · Drizzle schema Generated types Schema Zod · z.object Single source of truth Server tRPC router Input / output inferred Client Typed fetch call Autocomplete · no codegen CI Gate tsc --noEmit Blocks merge on mismatch
DB → Schematyped
Schema → Serverinferred
Server → Clientinferred
End-to-end0 any
06 — Numbers

Standards,
not anecdotes.

What every TypeScript build leaves with — the floor, not the ceiling.

Type coverage 0 strict · across last 12 builds
#StandardFloorMethod
01 Type coveragestrict mode, repo-wide 0% tsc
02 Runtime type errorscaught pre-prod 0 Sentry
03 tsc build timeincremental 0s CI
04 ESLint critical issuestype-aware rules 0 typescript-eslint
05 PRs blocked by red type-checkrare, by design 0 CI gate
06 Strict-mode adoptionrolled out 0% tsconfig
08 — Engagement

Three ways
to start.

01 / Sprint2 weeks
Diagnostic
sprint.
flatfixed scope
  • Tech audit · current TS config
  • Type-coverage baseline
  • Risk & cost map
  • Live walkthrough · written report
Book a sprint
02 / MVP— Most chosen
MVP ship.
retainer4–8 weeks
  • One product surface, end to end
  • Shared schema · client / server wired
  • Strict mode from commit one
  • CI/CD · type-check gate · runbook
  • Two rounds of post-launch iteration
Start an MVP
03 / Build12+ weeks
Ground-up
platform.
retainerquarterly
  • Multi-package monorepo platform
  • Internal admin + customer app
  • Embedded design partner
  • Hand-off plan, onboarded team
Plan a build
09 — Questions

Things people
actually ask.

Strict mode turns a category of production bugs — null references, mismatched shapes, silent `undefined` — into compile-time errors caught before a PR merges. The upfront cost is a slower first commit; the payoff is fewer 2am incidents and a codebase where refactors don't require a prayer. On a ten-year timeline, that trade is not close.
Yes — almost always incrementally, never a big-bang rewrite. We start with an `any`-audit to find where types currently lie, rename files `.js` → `.ts` package by package, and roll strict mode out file by file as coverage climbs. The build stays green the entire time.
tRPC when client and server live in the same TypeScript monorepo — it skips codegen entirely and the types are always in sync. We reach for ts-rest or a typed OpenAPI contract when the API needs to serve external consumers, mobile clients, or teams outside the monorepo who need a stable, documented REST surface.
`tsconfig.json` ships with `strict: true` plus `noUncheckedIndexedAccess` and `exactOptionalPropertyTypes` on every project we own. `any` is not banned outright — it's lint-flagged via typescript-eslint and requires an inline comment justifying why, reviewed like any other suppressed warning. In practice it appears almost exclusively at the boundary of an untyped third-party library.
Yes. When a dependency ships without types and DefinitelyTyped doesn't cover it, we write a scoped `.d.ts` shim — typing only the surface we actually call, not the whole library. That keeps the `any` boundary small, explicit, and easy to find later.
Vitest end to end — unit, integration, and type-level tests via `expectTypeOf`, all in the same runner that already understands your `tsconfig`. CI runs `tsc --noEmit` as its own gate before the test suite even starts, so a type error fails fast and never burns test-runner time.
10 — Start

Let's build
something worth typing.

Two-week diagnostic, four-week MVP, twelve-week ground-up. Bring the brief — we'll send a plan, not a pitch deck.

Start a project
Tweaks
Accent
Motion
Lenis
Sound