Why We Don't Use TypeScript for Everything
Type safety is important. But TypeScript's type system has limits that make certain architectures impossible.
Core Concept
TypeScript is the default choice for web development in 2026. “If you’re not using TypeScript, you’re shipping bugs.”
But here’s the problem: TypeScript’s type system is structurally typed, not nominally typed. This makes certain patterns impossible to encode safely.
The Constraint
Example: User IDs vs Post IDs
In TypeScript, both are string. The compiler can’t prevent you from accidentally passing a userId where a postId is expected.
type UserId = string;
type PostId = string;
function deletePost(postId: PostId) {
db.delete(postId);
}
const userId: UserId = "user_123";
deletePost(userId); // ❌ This compiles! But it's a bug!
Why this happens: TypeScript uses structural typing (if it looks like a string, it is a string). There’s no way to create truly distinct types.
Languages with nominal typing (Rust, Haskell, Elm) would catch this at compile time.
The Solution
We use TypeScript for 80% of code, but:
1. Critical Data Pipelines → Python
Why: Data transformations need pandas/numpy. TypeScript can’t touch this ecosystem.
Example: Processing 10TB of video analytics for LyveCom.
2. Performance-Critical Services → Rust
Why: TypeScript (Node.js) has GC pauses. Rust has zero-cost abstractions.
Example: Payment processing sidecar with sub-millisecond SLAs.
3. Mobile Apps → Dart (Flutter)
Why: Flutter compiles to native. TypeScript (React Native) uses a JavaScript bridge.
Example: All our mobile ventures (Lifework, Stella, Hobbyist).
4. Type-Critical Logic → Elm or Rust
Why: When correctness matters more than speed, we need stronger guarantees.
Example: Financial calculations, medical data processing.
The Architecture
Our stack for a typical venture:
Frontend Web: TypeScript (Next.js/Astro)
Mobile: Dart (Flutter)
API Layer: TypeScript (Node.js/Bun)
Database: SQL (Supabase/Postgres)
Worker Services: Rust (for hot paths)
Data Processing: Python (pandas/polars)
Why this works:
- TypeScript for 80% of code (easy hiring, fast iteration)
- Specialized languages for the 20% where TS fails
- Clear boundaries (no leaky abstractions)
The Trade-Off
What you lose:
- “One language to rule them all” dream
- Slightly higher complexity (more toolchains)
What you gain:
- Right tool for each job
- 10x performance where it matters
- Stronger type safety for critical paths
- Access to specialized ecosystems (ML, mobile, systems)
The Nuance
TypeScript is amazing for:
- Web applications (React, Svelte, Vue)
- API servers (Express, Fastify, Hono)
- Serverless functions
- Tooling and scripts
TypeScript is wrong for:
- Mobile native (use Flutter/Swift/Kotlin)
- Systems programming (use Rust/Go)
- Data science (use Python)
- Mission-critical safety (use Rust/Haskell)
The First Principle: Use the type system that matches your correctness requirements. For most web code, TypeScript is enough. For safety-critical code, it’s not.