It's 2021 and I still don't know the best way to write this in TypeScript.

February 10, 2021 (Syndicated From dev.to)

Below I have three things they’re not the same, but they’re not that different. They all actually have their own set of pros and cons. I wish it was actually much simpler to choose between them, and there was one way to do it that had the simplicity and brevity all in one.

If you know a better way to describe this data, please do tell.

Function

Functional and simple, but kind of hard to create a return type, unless you want that defined separately or use ReturnType<typeof person>. 😢

const person = (name: string) => {
  const initial = name.charAt(0);
  const length = name.length;
  const initialRegex = new RegExp(initial, 'g');
  const initialOccurance = (name.match(initialRegex) || []).length;
  return { initial, length, initialRegex, initialOccurance};
}

Class With Getters

Class based approach with getters, in my opinion the most elegant because it’s less redundant, no repetition of the names to export as above. However the caveat (or benefit) of not running everything at runtime is interesting, meaning, at initialization, no properties are processed, however they’re not cached either, so everytime you run this.initial it has to run that code again and again.

class Person {
  constructor (public name: string) {}
  get initial () {
    return this.name.charAt(0);
  }
  get initialRegex () {
    return new RegExp(this.initial, 'g');
  }
  get length () {
    return this.initial.length
  }
  get initialOccurance () {
    return (this.name.match(this.initialRegex) || []).length;
  }
}

This isn’t actually a fair contender because there’s no way to get an object with all of these properties. You’d need to add a .toJSON() method repetitively building up the properties again.

  toJSON() {
    return {
      name: this.name,
      initial: this.initial,
      length: this.length,
      initialRegex: this.initialRegex
    }  
  }

Class with Initialized Properties

This fixes the caching issue by having all the properties initialized with the constructor, but we get the repetition of having to define the types in the class now. 🙄

class Person {
  initial: string;
  length: number;
  initialRegex: RegExp;
  initialOccurance: number;
  constructor (public name: string) {
    this.initial = name.charAt(0);
    this.length = name.length;
    this.initialRegex = new RegExp(this.initial, 'g');
    this.initialOccurance = (name.match(this.initialRegex) || []).length;
  }
}

Why so many options? Why are none of them good?