Search code examples
typescript

How can I type a method with 'this' inside object literal in typescript?


const log = {
  counter: {
    a: 1,
    b: 2,
    c: 3,
  },
  increment(entry: keyof typeof this.counter){
    this.counter[entry]++;
  }
};

function incrementLog(entry:keyof typeof log.counter){
    log.counter[entry]++;
}

incrementLog('a'); // ok
incrementLog('d'); // error, must be 'a' | 'b' | 'c'
log.increment('a'); // ok
log.increment('d'); // no error

Playground Link

I want to enforce the argument type of increment method to be keyof typeof log.counter, which is 'a' | 'b' | 'c'. I can achieve it in the standalone function, but it doesn't work in the increment method: 'this' is not defined.

I've also tried log.counter instead of this.counter on the method definition, but that creates a 'circular initializer' which also doesn't work as intended.

I hope not to manually type the log or manually type the counter, because when I make changes to the object, I hope to only make changes in one place.


Solution

  • Define counter before log. You cannot reference type in the middle of expression which defines the type. You can easily avoid duplicating definition/initialization.

    const counter = {
        a: 1,
        b: 2,
        c: 3,
    };
    const log = {
      counter,
      increment(entry: keyof typeof counter){
        this.counter[entry]++;
      }
    };
    
    function incrementLog(entry:keyof typeof log.counter){
        log.counter[entry]++;
    }
    
    incrementLog('a'); // ok
    incrementLog('d'); // error, must be 'a' | 'b' | 'c'
    log.increment('a'); // ok
    log.increment('d'); // error, must be 'a' | 'b' | 'c'