TypeScript Best Practices for 2026
Modern TypeScript patterns every developer should know — strict mode, branded types, const assertions, discriminated unions, and more.
Author
Robert Baker
Published
Read time
2 min read
TypeScript has evolved rapidly. Patterns that were cutting-edge in 2023 are now table stakes. Here’s what modern TypeScript looks like in 2026.
Always Use Strict Mode
If your tsconfig.json doesn’t include "strict": true, you’re leaving type safety on the table. Strict mode enables:
strictNullChecks— catchesnull/undefinedbugsnoImplicitAny— forces explicit typingstrictFunctionTypes— correct function varianceexactOptionalPropertyTypes— distinguishesundefinedfrom missing
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true
}
}
Branded Types for Domain Safety
Branded types prevent mixing up values that share the same primitive type:
type UserId = string & { readonly __brand: "UserId" };
type OrderId = string & { readonly __brand: "OrderId" };
function getOrder(orderId: OrderId) { /* ... */ }
const userId = "usr_123" as UserId;
const orderId = "ord_456" as OrderId;
getOrder(userId); // Type error — can't pass UserId as OrderId
getOrder(orderId); // Works
This catches an entire class of bugs at compile time with zero runtime cost.
Discriminated Unions Over Enums
Prefer discriminated unions for state modeling. They’re more powerful than enums and work naturally with narrowing:
type ApiResult<T> =
| { status: "loading" }
| { status: "error"; error: Error }
| { status: "success"; data: T };
function handleResult(result: ApiResult<User>) {
switch (result.status) {
case "loading":
return <Spinner />;
case "error":
return <ErrorMessage error={result.error} />;
case "success":
return <UserCard user={result.data} />;
// TypeScript ensures exhaustive handling
}
}
satisfies for Type Validation
The satisfies operator validates a value against a type without widening it:
const routes = {
home: "/",
about: "/about",
blog: "/blog",
} satisfies Record<string, string>;
// routes.home is typed as "/" (literal), not string
Use as const for Immutable Data
const HTTP_METHODS = ["GET", "POST", "PUT", "DELETE"] as const;
type HttpMethod = (typeof HTTP_METHODS)[number];
// HttpMethod = "GET" | "POST" | "PUT" | "DELETE"
Prefer unknown Over any
When you genuinely don’t know a type, use unknown instead of any. It forces you to narrow before use:
function processInput(input: unknown) {
if (typeof input === "string") {
return input.toUpperCase(); // Safe — narrowed to string
}
if (input instanceof Error) {
return input.message; // Safe — narrowed to Error
}
throw new Error("Unexpected input type");
}
Template Literal Types
Build complex string types from simpler ones:
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type ApiRoute = `/api/${string}`;
type Endpoint = `${HttpMethod} ${ApiRoute}`;
// "GET /api/users" | "POST /api/users" | ...
Key Takeaways
- Enable
strictmode andnoUncheckedIndexedAccessin every project - Use branded types for domain identifiers
- Model state with discriminated unions, not enums
- Prefer
satisfiesover type annotations when you want literal types preserved - Ban
anyfrom your codebase — useunknownand narrow
TypeScript’s type system is one of the most powerful in mainstream programming. These patterns help you use it to its full potential.
Share this article
Get expert development help fast
Our engineering team turns complex ideas into production-ready software tailored to your business.
Post essentials
- Published on January 10, 2026 with real-world implementation examples.
- Designed for fast implementation with 2 min read worth of guidance.
- Validated by Robert Baker team.
Expert contributor
Robert Baker
Robert Baker cares deeply about reliable, well-architected solutions. Every guide we publish is battle-tested in real projects before it reaches the blog.
Browse more articlesShare article
Help your peers level up — share this article with colleagues who'd find it useful.
Email this articleContinue leveling up your engineering skills
Dive deeper with related guides chosen to complement this topic and accelerate your next project.
Field-tested Choosing the Right Tech Stack for Your Project
A framework for evaluating technologies and making informed stack decisions. Avoid hype-driven development and pick tools that match your actual requirements.
Field-tested React vs Next.js: When to Use Each in 2026
A practical comparison of React SPA and Next.js for different project types. Learn when a simple React app is enough and when you need server-side rendering.
Field-tested Securing Your Web Application: A Developer's Checklist
Essential web application security practices covering OWASP top 10, authentication, CORS, CSP headers, and common vulnerabilities every developer should address.
Get engineering insights every week
Subscribe for framework updates, architecture patterns, and deep dives tailored to busy engineering teams.
Subscribe to Our Newsletter
Get tech tips, special offers, and updates delivered to your inbox.