58

I have a bunch of data-only "classes" (in .NET world we call them POCO objects) that does not have any methods or even constructors. Examples are Customer, Product, User entities, you name it...

Originally I started using typescript classes but now I'm thinking that declaring them as interface might be better. From performance standpoint, and not only... It's just that in C# we're used to use interfaces for different thing, and for "POCO" (Plain-old-clr-object, or "data-only" object) we use just a class (sometimes even struct).

What is a proper way to declare them in TypeScript?

Note that I mostly understand (I think) technical differences between class and interface (i.e. that interface is a compile-time construct), but I'm trying to find out which one fits this case semantically.

P.S.: I've seen similar questions (like this) but none of them adress this specific issue clearly and definitely, so please don't close this as 'possible duplicate' or 'opinion-based' (cause it isn't) :)

3
  • 2
    use an interface. Commented Dec 9, 2016 at 20:05
  • 2
    One obvious semantic difference is that classes can only be created by calling a constructor with a new. The established way of representing data-only object in javascript is JSON, using classes for that just seems weird. With interfaces and structural types, you have the nice property that any data-only object, regardless of where it came from and how it was initially declared, typechecks as soon as it conforms to the interface: interface Person { name: string; }; var p: Person = { name: 'X' }; Commented Dec 10, 2016 at 0:24
  • For example , classes are not recommended for Redux store structure declaration as they are not serilizable. github.com/reduxjs/redux/issues/4649#issuecomment-1872408256 Commented Dec 30, 2023 at 1:22

4 Answers 4

47

Use Interface, class is not even close.

People start writing TypeScript and they suddenly think they have to use classes for some reason. But they don't. Classes are an ES6 feature and they work fine, but if it's just data, it's just data.

A major problem with using classes is that they won't serialize/deserialize like you expect over the wire, so things like instanceof checks won't work.

One rule of thumb is that if there's not internal state associated with some methods, and there's no need for traditional OO polymorphism, don't use a class. This even extends to static classes -- use namespace / module instead.

Sign up to request clarification or add additional context in comments.

2 Comments

this is a bit of waking the dead here.. but i was asking this exact q earlier. and wondering how you would use just an interface for it? my thinking then is that you need to add an interface and duplicate the fields into both the "container" as well as the "interface" or am i missing something?
You can also consider Type instead of Interface. stackoverflow.com/questions/37233735/…
34

Use classes with parameter properties:

// Immutable data object
class Person {
  constructor(readonly firstName: String, readonly lastName: String) {}
}

// Mutable data object
class Person {
  constructor(public firstName: String, public lastName: String) {}
}

2 Comments

Can anyone comment on this vs. interfaces? I like both, but don't know what to choose. The parameter properties seem like a nice alternative/better version if you want to extend the classes later...
There is a semantic argument for this style of class over interfaces. In cases where you don't need to send the object over the wire (for example some sort of UI property), and you do want to specify some information via a class, then one could argue the use of a class is easier to read/understand than an interface.
0

To store data-only objects you should use POJO, and in Typescript describe structures using interfaces/types

If you want to store data, use an object or an array.

If you want data with attached logic, use a class.

Storing data without attached logic in a class is a misuse of features of your programming language

From https://github.com/reduxjs/redux/issues/4649#issuecomment-1872426846

Note that classes are not specific to TypeScript, they are a JavaScript feature.

Comments

-2

I use classes for my data in Typescript, as I allways did in C# C++ Java, and only use interfaces for dependency injection. Interfaces have not be thought for manipulating data.

In my application model, if I need to write a method that uses some datas of the same class, then the class is better place to go for that method. Adding getters and setters that transform your properties is a great flexibility.

I am not a javascript programmer so when I need to create an object, I don't like using data only object where properties can by anything. I create an instance of class by the way of the constructors that have been defined for that class.

When I receive data from a service, I don't deserialize a class: I deserialize the json data and I create my instance with that data. Here is the way for building my model from the received data:

// ajax callback for diaries
onReceiveDiary( jsonDiary : any )
{
   let newDiary = new Diary ( jsonDiary );

   // now I can call methods on the object:
   let ok : boolean = newDiary.CheckIfCompleted();
}

In the class I add a constructor with the only one dependency on the json object:

export class Diary
{
   title : string;
   article : Article;

   constructor( json : any )
   {
      // the trick for setting all the object properties
      $.extend( this, json);

      this.article = new Article( json.article );
   }
}

Or we can create a factory for building objects using the default constructor:

   let newDiary = new Diary ();
   $.extend( newDiary, jsonDiary );
   newDiary.article = $.extend( new Article(), jsonDiary.article );

4 Comments

if I need to write a method that uses some datas of the same class, then the class is better place to go for that method - that couples the method to that class and makes the method unusable for anything else. A free function (not a method) that takes an object declared as interface can be used on any data that conforms to that interface.
...and only one class will implement that interface, because what defines a class is its properties, no ? If you use a javascript object for implementing an interface you are not sure at compile/tsc time the object behind will have the properties required by your method at runtime. So I use classes to implement interfaces that are used by decoupled methods :)
No, if the object is created by strictly typed typescript code (no type casts), typechecker will ensure that it has all properties declared in the interface. The point is that the code that creates the object does not need dependency neither on class nor on interface. That's liberating :)
Implementation of classes in JavaScript is different to many other OOP languages, github.com/reduxjs/redux/issues/4649#issuecomment-1872502714

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.