Frontend Development 8 min read

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.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Why We Avoid Using interface and type for Business Data Structures in TypeScript

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.

design patternsfrontendtypescriptdecoratorstypeinterface{}class
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.