Ruan Mendes
Ruan Mendes

Reputation: 92274

Forcing objects within objects to be of same type in TypeScript

I need to create a list of constants, e.g.,

const Days = {
  YESTERDAY: -1,
  TODAY: 0,
  TOMORROW: 1,
}

I would like a way to constrain the types of all properties in Days, that is, if I add a property BAD_DAY: true, I would like the compiler to complain.

I started by creating something like

type ObjectOf<T> = {[k: string]: T};

const Days: ObjectOf<number> = {
   A: true;
}

Which does give me an error, however, I don't get type completion when I hit ctrl-space after Days.. I understand it's because I made it a keyed object type.

I can either get code completion as in the first example, or compiler help with the second example. Can I have my cake and eat it too? I guess I want something that behaves like Java Enums in the sense that it's a known list of objects of the same type.

enum Days{
   Today("SUN"), MONDAY("MON"), TUESDAY("TUES"), WEDNESDAY("WED"),
   THURSDAY("THURS"), FRIDAY("FRI"), SATURDAY("SAT");
   private String abbreviation;
   public String getAbbreviation() {
       return this.abbreviation;
   }
   Days(String abbreviation) {
      this.abbreviation = abbreviation;
   }
}

Upvotes: 1

Views: 159

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249536

To have your cake and eat it too. With regard to the const you need a generic helper function. The helper function will enforce the constraint, but infer the true type of the passed in object literal:

type ObjectOf<T> = {[k: string]: T};
function createObjectOfNumber<T extends ObjectOf<number>>(v:T){
    return v;
}
const Days = createObjectOfNumber({
   A: 1
   // B: true // would be an error
});
Days.A // ok

Or a more generic version:

function createObjectOf<TValue>(){
    return function<T extends ObjectOf<TValue>>(v:T){
        return v;
    }
}
const Days = createObjectOf<number>()({
   A: 1
   // B: true // would be an error
});
Days.A // ok

If you want something like Java enums, there is no language support for that in Typescript, but you can simulate them, see this answer

Upvotes: 1

Related Questions