• JavaScript
  • Computer Programming

Class Expressions in JavaScript

November 10, 2022 • 1 min read

Like function expressions, you can create class expressions and run them the same way. They can be useful!

I learned you can create class instances pretty easily with class expressions. As you might have already learned from my other post on self invoking function expressions, in JavaScript you can utilize function expressions to immediately run some code or preserve state. You can do the same with class expressions.

Class Expression Syntax

In the following snippet we implement the CarAPI using a class expression.


1
interface CarAPI {
2
start(): Promise<void>
3
stop(): Promise<void>
4
getSpeed(): number
5
}

To create our class instance we just do:


1
const car = new (class implements CarAPI {
2
start() {
3
return Promise.resolve()
4
}
5
stop() {
6
return Promise.resolve()
7
}
8
getSpeed() {
9
return 30
10
}
11
})

To use our car we can call an API method from the car instance like we do with normal class instantiations.


1
// 30;
2
console.log(car.getSpeed());

Extending Class Expressions

You can also use the extend keyword to create a new class instance that extends from a base class.


1
const superCar = new (class extends Car {
2
getSpeed() {
3
return 300
4
}
5
});
6
7
// 300
8
console.log(superCar.getSpeed());
9
superCar.start().then(() => {
10
console.log('Car started...')
11
})

Since it is an expression we can also opt to evaluate it inline.


1
const superCarSpeed = new (class extends Car {
2
getSpeed() {
3
return 300
4
}
5
})().getSpeed();
6
7
// 300
8
console.log(superCarSpeed)

When to use it

I have found that class expressions are useful when I need to quickly implement mock implementations of real class instances for unit tests. They also allow you to easily overwrite class API methods for providing different implementaions of the same API. This can also be done with the Object syntax implementation. For example I can implement the CarAPI like this as well:


1
const objectCar: CarAPI = {
2
start() {
3
return Promise.resolve()
4
},
5
stop() {
6
return Promise.resolve()
7
},
8
getSpeed: () => 30
9
}

This syntax makes it easy to extend and overwrite implementations as well. However, it does not allow for usage of class specific constructs in your code like instanceOf. As a result, if you were providing mock implementations of CarAPI in your test and used instanceOf internally to check what kind of Car you have, this will break your test. When I faced this similar problem with some code I was working on, utilizing class expressions helped fix the misalignement between test and product code giving me a clean test pass 😁