Why We Avoid Using interface and type for Business Data Structures in TypeScript
The article explains why declaring business data structures with TypeScript's interface or type is discouraged, illustrates practical problems such as property name changes and type mismatches, and advocates using classes to gain decorator support, combined behavior and data, and better extensibility.
In a previous post the author mentioned that business data structures should not be declared with interface or type in TypeScript, which sparked many questions. This article explores the reasons behind that recommendation.
1. Property name changes become painful – When a backend decides to rename a field (e.g., .name to .realName ), a simple search‑replace would affect dozens of files and break many usages, making maintenance risky.
2. Sudden type changes break existing code – A boolean flag disable may need to evolve into an enum with values 0, 1, 2. Changing the type from boolean to number forces a massive refactor and can leave some users unable to operate.
3. Interfaces/types cannot carry behavior – They only describe shape; they do not bind methods to the object. Trying to add methods like eat() requires casting to Object or using a class, which defeats the purpose of the type declaration.
interface IUser {
name: string
}
type TUser = {
name: string
}
const userI: IUser = { name: 'Hamm' }
const userT: TUser = { name: 'Hamm' }
console.log(userI)
console.log(userT)Using a class solves the above issues because a class can declare both properties and methods, be decorated, and participate in inheritance.
class User {
name!: string
eat() {
console.log(`${this.name} eating...`)
}
}
const user = new User()
user.name = 'Hamm'
user.eat()
console.log(user)Why we prefer classes
Only classes, their properties, methods, and parameters can be annotated with decorators, enabling powerful metadata and runtime features.
Classes combine data and behavior, allowing methods such as isDisabled() to be defined once instead of scattered checks.
Abstract classes and abstract properties let us implement design patterns that are otherwise cumbersome with plain types.
Classes fit naturally with object‑oriented paradigms while still allowing functional programming techniques.
We still use interface for design‑pattern contracts and decorator parameters, and type mainly as aliases, but business data structures are declared as classes. For external JSON structures we keep using plain objects.
Finally, the author provides a tiny generic interface IJson<V = any> to illustrate a sarcastic example and points readers to the source repository on GitHub and Gitee for the full code.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
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.