React/Typescript And Class Objects

When working with react and typescript you would easily forget that JavaScript has support for classes since typescript prefers to use the more loosely defined types for objects. As a result, some people would think that classes don't have any value in modern JavaScript anymore, but I beg to differ.

As I have mentioned in a couple of earlier blog posts, it may be difficult to use objects properly when using react, as react relies completely on the detection of object modifications. That is, if you pass an object as a prop, this prop will only cause the component to re-render if it gets swapped for a new object. With a new object, I mean a new address. Whether this is a completely new object, a shallow clone, or a deep clones doesn't matter, as all of them will trigger a re-render. Updating a field or member of the object directly (i.e x.f = 'a') will not trigger a re-render.

This behavior has as direct consequence that you typically create a lot of copies in react, for which the spread operator is quite often used: {...object, f: 'a'} as this does exactly what react wants. It creates a shallow copy of the object and only overwrites the f field.

The Typescript compiler has some very nice features to work efficiently with types, like how it can detect which type of a union type you are working with depending on the value of a field:

type Dog = {
  sound: "woof";
}

type Cat = {
  sound: "miauw";
}

type Animal = Cat | Dog

const animal: Animal = ...
if (animal.sound === "woof") {
  // The compiler knows this is a dog.
}

I have used this feature to write cleaner code for response handling and other cases. It doesn't handle all cases where I know for certain something must be of a specific type, but I also heard they are working on improving this and keep on adding cases.

All of this makes it clear that types are a very powerful feature, so why still bother with classes? Well, because classes can do many things that types can't. First of all they can have methods, which can do something differently depending on the specific class. Moreover, they can avoid a lot of superfluous duplication. For instance, the example above would force me to always copy the sound of an animal when I want to create a new one. They can also make your code more readable and easier to maintain, especially the usage of static factories can help with this.

// Using a class
const dog = Animal.dog("Tobe");

// Using types
const dog = {
  sound: "woof",
  name: "Tobe"
}

magine we want to change the sound of the dog, when we would have used the type, we would have to either rely on search and replace or on the IDE to change it everywhere or we will get lots of compile errors. In the case of the class, we only have to change it in the class itself and it works itself out. If you really don't like classes, I would still encourage you to have factory methods to create the objects for you to avoid duplication.

Do you still use classes in your React application or have you gone all out with types? If so, do you think classes can help you improve your code? What are some of the challenges you foresee?