Suggest an editImprove this articleRefine the answer for “Typing for the sake of typing”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**"Typing for the sake of typing"** is when a developer adds or complicates types without solving a real problem, just to have "everything typed" - types for the sake of a checkbox, not for understanding, safety, or readability. **Key point:** typing should solve a problem, not prove that you know TypeScript - type the interaction interfaces, not the implementation details, and trust type inference wherever the compiler already knows the answer.Shown above the full answer for quick recall.Answer (EN)Image## What "typing for the sake of typing" means > This is when a developer **adds or complicates types** > without solving a real problem, > just so that "everything is typed". In simpler terms: > "Types for the checkbox", > not for **understanding, safety, and readability** of the code. --- ## Examples of "typing for the sake of typing" ### 1. Types that add nothing ```javascript const name: string = "Alex"; // redundant ``` TypeScript would infer the type `string` anyway - you just repeated the obvious. Better: ```javascript const name = "Alex"; ``` --- ### 2. Duplicating a structure for no reason ```javascript type User = { id: number; name: string; }; function getUser(): { id: number; name: string } { // the types are duplicated return { id: 1, name: "Tom" }; } ``` Better: ```javascript function getUser(): User { return { id: 1, name: "Tom" }; } ``` --- ### 3. Unnecessary generics ```javascript function identity<T>(value: T): T { // fine, a basic example return value; } function double<T extends number>(x: T): number { // the generic is useless return x * 2; } ``` Here `T` carries no value at all. Simpler: ```javascript function double(x: number): number { return x * 2; } ``` --- ### 4. Re-typing when it is not needed ```javascript const user = { name: "John" } as { name: string }; // pointless ``` TypeScript already understands this is `{ name: string }`. --- ### 5. Overly deep data typing ```javascript type Config = { features: { flags: { experimental: { alphaMode: boolean; betaUI: boolean; }; }; }; }; ``` It sounds "strict", but it is often simpler to describe it partially: ```javascript type Config = Record<string, any>; // or Partial<Record<string, boolean>> ``` **Typing should reflect the substance, not the shape of documentation.** --- ## Why this is an antipattern ### 1. Loss of flexibility Excessive typing gets in the way of working with real, changing data. Example: ```javascript type User = { id: number; name: string; age: number }; function updateUser(user: User) { user.id = 123; // ok user.nickname = "coolguy"; // not allowed, even if the API really returns this field } ``` The code became **too rigid** - instead of protection, you got "stone walls". --- ### 2. More complexity for no benefit Sometimes developers do "type math" to derive a *perfectly precise type* that nobody can later understand. Example: ```javascript type Flatten<T> = T extends (infer U)[] ? U : T; type DeepPartial<T> = { [K in keyof T]?: DeepPartial<T[K]> }; ``` This is elegant and useful in a library, but in an ordinary application it is excessive and hurts readability. --- ### 3. Less benefit, more noise Often types start getting in the way instead of helping: ```javascript function sum(a: number, b: number): number { return a + b; } ``` This is correct, but with 1000 such declarations the code becomes "noisy", and the IDE already infers types from context anyway. --- ### 4. A false sense of security "Typing for the sake of typing" creates the illusion that everything is safe, but in reality it might not be. Example: ```javascript interface User { id: number; name: string; } const user = {} as User; // tricking TypeScript console.log(user.name.toUpperCase()); // runtime crash ``` The types are there, there are no errors, but the program still crashes. Typing is not the same as data validation. --- ### 5. Harder to refactor and maintain When types are overly detailed or redundant, every code change requires cascading type edits. Example: ```javascript type Product = { id: number; title: string; price: number }; type ProductResponse = { data: { items: Product[] }; meta: { total: number } }; ``` If the API changes its structure, you have to fix dozens of types, even if the code's logic did not change. --- ## 6. Compilation performance drops TypeScript compiles and checks every type, including unnecessary and artificially complicated ones. In large projects **this genuinely slows down builds**. Especially if you use complex conditional types and `infer` without a real need. --- ## 7. Violating the principle "typing is not logic" Some developers start "hiding business logic in types": Example: ```javascript type Access<T extends Role> = T extends "admin" ? AdminPanel : T extends "user" ? UserDashboard : GuestPage; ``` It looks clever, but: - it is harder to understand; - the IDE loses its hints; - and the logic should live in the code, not in the types. --- ## How to tell you are stuck in the "typing for the sake of typing" trap Here is a symptom "checklist": | Symptom | Sign of the antipattern | |---|---| | You write a type that TS could have inferred itself | redundant | | You have more type code than logic | overload | | You often have to write `as` | the type model is flawed | | Types look like "math" and are hard to read | over-complication | | Every refactor breaks 20 types | over-engineering | | You feel like adding "one more generic for elegance" | a warning sign | --- ## The right approach: pragmatic typing > Typing should **solve a problem**, > not prove that you know TypeScript. ### Principles: 1. **Type the interaction interfaces**, not the implementation details. (function inputs/outputs, APIs, contracts between modules) 2. **Trust TS's type inference** - do not write `:string` if the compiler already knows it. 3. **Use** `as const`**,** `ReturnType<>`**,** `typeof` so you do not duplicate types. 4. **Code first, type later** - do not build the type system "ahead of the code". 5. **Do not be shy about** `any` **or** `unknown` **locally** if it speeds up development, as long as the interfaces stay strict. 6. **The closer a type is to business logic, the simpler it should be.** --- ## An example of "good typing" ```javascript function fetchUser(id: number) { return fetch(`/api/users/${id}`) .then(res => res.json() as Promise<{ id: number; name: string }>); } ``` The type describes the **function's contract**, not every intermediate step. It is short, clear, and protects against real errors. --- ## Summary | Question | Answer | |---|---| | What is "typing for the sake of typing"? | A redundant or meaningless description of types that brings no real benefit | | Why is it an antipattern? | It complicates the code, slows down builds, creates false security, and hinders the project's growth | | How do you know you are stuck in the trap? | More types than logic, frequent `as`, everything breaks at the smallest change | | What is the right approach? | Type the interfaces and boundaries between modules, not the internal details, and use type inference | --- **In simple terms:** > Good typing is like insurance: > it protects against real risks, > not straps 20 belts onto a single bicycle. > > **TypeScript is about meaning, not syntax.**For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.