Henrik Sommerfeld

Alternative to Typescript Classes that can be Compared

When building a piece of software that has become quite complex, the choise of NodeJS and Typescript feels less and less convincing. C# or Java might have been a better fit, but here we are. We found that using classes help us avoid misstakes. The initial use of string and number for everything resulted in double parsing and made refactoring harder.

So, by using classes we became more confident in writing logic, like Time.parse('18:30').add(Minutes.parse(10)) (with the actual values being user input or reads from a database). But a downside of using classes is the inability to use simple === comparison.

if (Time.parse('18:30') === Time.parse('18:30')) {
  // nope
}

This was still a step forward from passing numbers and strings around, so we made more classes, like one for UUID.

When Uuid is a class in the code below, we will not find what we’re looking for, since the instances we’re comparing are not the same (eventhough they might have the same value). It’s also type-wise nothing wrong with the code, so we won’t have any compilation issues hinting that we may have made a mistake (the has function will always return false unless we’re comparing the same class instances).

const agreementIds: Set<Uuid> = await getFromSomewhere()
const relevantEmploments = employments.filter(e => agreementIds.has(e.agreementId))

Using unique symbols

If we insted of using a class, implement the Uuid as a unique symbol type combined with functions in a module, we can compare two values as if they were regular strings.

// uuid.ts
import assert from 'assert'
import { randomUUID } from 'crypto'

type Uuid = string & { readonly whatever: unique symbol }

const Uuid = {
  parse(input: string) {
    assert(validUuidRegex.test(input), 'invalid uuid')
    return input as Uuid
  },

  create() {
    return randomUUID() as Uuid
  },
}

const validUuidRegex =
  /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i

export default Uuid

This works good for anything that is essentially a value that we don’t have a need to perform operations on, like dividing one such value with another one. The same code for finding relevant employments will do what we intended with this new Uuid implementation.

No matching posts found. You can use wildcards and search only in titles, e.g. title:iot
Loading search index, please wait...
Search index failed to download 😢