Typing for the sake of typing
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
const name: string = "Alex"; // redundantTypeScript would infer the type string anyway - you just repeated the obvious.
Better:
const name = "Alex";2. Duplicating a structure for no reason
type User = {
id: number;
name: string;
};
function getUser(): { id: number; name: string } { // the types are duplicated
return { id: 1, name: "Tom" };
}Better:
function getUser(): User {
return { id: 1, name: "Tom" };
}3. Unnecessary generics
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:
function double(x: number): number {
return x * 2;
}4. Re-typing when it is not needed
const user = { name: "John" } as { name: string }; // pointlessTypeScript already understands this is { name: string }.
5. Overly deep data typing
type Config = {
features: {
flags: {
experimental: {
alphaMode: boolean;
betaUI: boolean;
};
};
};
};It sounds "strict", but it is often simpler to describe it partially:
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:
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:
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:
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:
interface User {
id: number;
name: string;
}
const user = {} as User; // tricking TypeScript
console.log(user.name.toUpperCase()); // runtime crashThe 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:
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:
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:
- Type the interaction interfaces, not the implementation details. (function inputs/outputs, APIs, contracts between modules)
- Trust TS's type inference - do not write
:stringif the compiler already knows it. - Use
as const,ReturnType<>,typeofso you do not duplicate types. - Code first, type later - do not build the type system "ahead of the code".
- Do not be shy about
anyorunknownlocally if it speeds up development, as long as the interfaces stay strict. - The closer a type is to business logic, the simpler it should be.
An example of "good typing"
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.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.