Data Structures in TypeScript

March 28, 2016

Took some time off this weekend to learn some TypeScript, and reimplemented some data structures as practice.

I don’t think I’ll continue to use much TypeScript moving forward, because it seems to promote the classical inheritance style of thinking in a language that doesn’t need or want it.

TL;DR: Prototypical/concatenative inheritance is much nicer than classical inheritance.

That said, first-class support for TypeScript in Visual Studio Code is quite awesome. While implementing the data structures, I came up with a TypeScript/prototypical hybrid style for writing object factories. In this hybrid style, the only place I’m writing any TypeScript is using interfaces for prototypes. Let’s take a number class for example:

interface NumberInterface {
  isEven()              : boolean
  multiplyByTwo()       : number
  divideBy(arg: number) : number
}

const number = (num: number) => {
  const prototype: NumberInterface = {
    isEven() {
      return this.number % 2 === 0
    },
    multiplyByTwo() {
      return this.number * 2
    },
    divideBy(arg) {
      if (arg === 0) {
        throw new Error('Cannot divide by 0')
      }
      return this.number / arg
    }
  }

  return Object.assign(Object.create(prototype), { number: num })
}

const two = number(2)
console.log(two.isEven())        // true
console.log(two.multiplyByTwo()) // 4
console.log(two.divideBy(2))     // 1
console.log(two.divideBy(0))     // Error: Cannot divide by 0

I return a object whose prototype is prototype using Object.create, and its initial state using Object.assign.

This style allows VSC to shout at me if the prototype doesn’t implement the interface correctly. It’s nice to have, but not worth switching over to a TypeScript workflow from the Babel workflow that I’m already used to.