TypeScript Ergonomic Brand Checks<!-- --> | <!-- -->Patrick Desjardins Blog
Patrick Desjardins Blog
Patrick Desjardins picture from a conference

TypeScript Ergonomic Brand Checks

Posted on: February 4, 2022

In short, the term "Ergonomic Brand Checks" is linked to branding. Branding is a way to dynamically check for a type. It comes with JavaScript being schemaless. In JavaScript, you need to check for a field/property that exist on an object to ensure you are manipulating an object desired. For example, if you have an array of different objects, you might want to check if you are modifying a Person or an Animal before accessing (read or write) the object.

With "Ergonomic Brand Checks" we are especially properties of an object. What is worth talking about is that TypeScript 4.5 allows checking private fields using the in operator.

1class Person {
2 #shortname: string;
3 public constructor(name: string) {
4 this.#shortname = name;
5 }
6
7 public static isPerson(obj: unknown): unknown {
8 return obj &&
9 typeof obj === "object" &&
10 #shortname in obj;
11 }
12}
13
14class Animal {
15 #shortname: string;
16 public constructor(name: string) {
17 this.#shortname = name;
18 }
19}
20
21const x1 = { shortname: "Test" };
22const x2 = new Person("Test2");
23const x3 = new Animal("Test3");
24console.log(Person.isPerson(x1)); // False
25console.log(Person.isPerson(x2)); // True
26console.log(Person.isPerson(x3)); // False

Line 10 highlights and presents the newest addition for ergonomic brand check-in TypeScript. The in operator within the static function of a class is used to check if a private field exists. Oddly, the function does not return a boolean but unknown. Changing the parameter type to any gives an output of any. However, the output is true or false when executing the code.

An interesting observation is that the last line returns false when we pass an instance of the class Animal even though the Person and Animal classes share the same field name. Actually, the value is also not relevant. The previous example modified to have the static function relying on a field that is not used but defined.

1class Person {
2 #brand: unknown;
3 #shortname: string;
4 public constructor(name: string) {
5 this.#shortname = name;
6 }
7
8 public static isPerson(obj: unknown): unknown {
9 return obj &&
10 typeof obj === "object" &&
11 #brand in obj;
12 }
13}
14
15class Animal {
16 #brand: unknown;
17 #shortname: string;
18 public constructor(name: string) {
19 this.#shortname = name;
20 }
21}
22
23const x1 = { shortname: "Test" };
24const x2 = new Person("Test2");
25const x3 = new Animal("Test3");
26console.log(Person.isPerson(x1)); // False
27console.log(Person.isPerson(x2)); // True
28console.log(Person.isPerson(x3)); // False

The trick of using unsused private property has been there for a while. What is new is the possibility to use the in. I'll conclude by referring to a great article by Michal Zalecki about four ways to nominal typing techniques in TypeScript.