8 Underrated TypeScript Features That Can Save Your Code
This article showcases eight often‑overlooked TypeScript capabilities—discriminated unions, as const,{ } tuples, template literal types, keyof + typeof, strict mode, noUncheckedIndexedAccess, and type augmentation—each with concrete examples and practical guidance on how they improve type safety and reduce boilerplate.
TypeScript offers many subtle features that dramatically improve code safety and developer productivity. The article walks through eight of the most underestimated capabilities, providing real‑world examples and explaining why ignoring them can lead to fragile code.
1. Discriminated Unions – Smarter switch statements
Discriminated unions let you model API responses with a type field that narrows the shape of each variant. Example data:
{ type: "h1", content: "Welcome" } { type: "image", src: "hero.png" } { type: "text", content: "Hello world" }TypeScript definition:
export type Element =
| { type: "h1"; content: string }
| { type: "image"; src: string }
| { type: "text"; content: string };Using a switch on element.type yields fully typed branches without needing undefined checks.
2. as const – Turn arrays into literal tuples
Without as const, const roles = ["admin", "user", "guest"] is inferred as string[]. Adding as const makes it a readonly tuple, allowing extraction of a union type:
const roles = ["admin", "user", "guest"] as const;
type Role = typeof roles[number]; // "admin" | "user" | "guest"This eliminates duplicate literals and typo‑prone enums.
3. Tuples – Strongly typed fixed‑length arrays
TypeScript tuples are simple to declare: type Pair = [string, number]; They guarantee length and element types, useful for coordinates, key‑value pairs, or any position‑sensitive data. Adding extra elements triggers a type error, providing safety.
4. Template Literal Types – Dynamic string unions
Combine literal unions to generate string combinations without repetition:
type Language = "en" | "de";
type Field = "title" | "description";
type TranslationKey = `${Language}_${Field}`; // "en_title" | "en_description" | "de_title" | "de_description"This improves readability, scalability, and eliminates manual duplication.
5. keyof + typeof – Extract object keys as a type
Given an object:
const colors = { primary: "#000000", secondary: "#ffffff" };You can derive a union of its keys:
type ColorName = keyof typeof colors; // "primary" | "secondary"This is handy for theme systems, form field names, flags, and configuration keys.
6. Strict Mode – Gradual adoption for beginners
Start with "strict": false in tsconfig.json, add types incrementally, then flip the switch to true. This approach eases the learning curve while eventually enforcing comprehensive type safety.
7. noUncheckedIndexedAccess – Safer array indexing
Without this flag, accessing arr[0] is typed as string even if the array might be empty. Enabling the option makes the result string | undefined, catching potential runtime errors early.
8. Type Augmentation – Extending existing types
When adding custom properties to globals like window, declare the augmentation:
declare global {
interface Window { myAppVersion: string; }
}
window.myAppVersion = "1.0.0";This satisfies the compiler and is essential for extending library types, adding globals, or customizing framework typings.
Overall, these small but powerful TypeScript features reduce bugs, cut boilerplate, and make everyday development smoother. Readers are encouraged to experiment and suggest any missing features.
Code Mala Tang
Read source code together, write articles together, and enjoy spicy hot pot together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
