Converting an interface into a class

Interfaces in TypeScript are great, but you don’t need them if you’ve already got a class that will do the job.

Last time I started a React app to help me organize my family history. I started with an interface for a person:

export interface IPerson {
  name: string;
  birth: Date;
  death: Date;
}

Because I had a React component called Person, I couldn’t name the interface Person as well without throwing a warning message. So after thinking about it, I decided to rename the component PersonCard, and use a Person class for creating a person instead of an interface.

Using a class instead of an interface

export default class Person {
  name: string;
  birth: Date | null;
  death: Date | null;
  constructor(name: string, birth?: string, death?: string) {
    this.name = name;
    this.birth = birth ? new Date(birth) : null;
    this.death = death ? new Date(death) : null;
  }
}

The Person class has a name property which is a string, and a birth and date property which can be either a Date or null, if say the date is unknown.

Now instead of creating a person like this, where I’m using the IPerson interface to provide structure:

const person: IPerson = {
  name: "Henry Michael Whittenberg”,
  birth: new Date("1710-01-01”),
  death: new Date("1767-01-19"),
};

I can now do it like this:

const person = new Person(
  "Henry Michael Whittenberg”,
  "1710-01-01”,
  "1767-01-19"
);

Note that I’m passing strings as parameters for the birth and death date, not an instance of the Date object. That’s because the Person class converts the optional birth and death dates from a string to Date objects.

Conditionally rendering a fact

Since the birth and death date are optional, I want to update my Fact component so it won’t show facts that have no values.

const Fact = (props: { fact: IFact[] }) => {
  const [key, value] = props.fact;
  return (
    <>
      {value && (
        <>
          <dt>{key}</dt>
          {value instanceof Date && (
          <dd>{value.toLocaleDateString()}</dd>
          )}
          {typeof value === "string" && <dd>{value}</dd>}
        </>
      )}
    </>
  );
};

By adding value &&, I’m able to wrap the fact description inside an inline condition so it will only display if there’s a value. You might notice that I was already using conditional checks to render different output if the value was a string or date.

What’s next?

The next step is to start working on handling dates, in case I don’t have a complete date. I need to be able to specify if someone was born about, before or after a date.

In the case of Henry, I’d like to change his birthdate to mean “About 1710” rather than mean “January 1, 1710”. To do this, I probably need to create an Event class that has methods for setting those dates.