2

I am trying to get typescript type-queries to work in classes.

Normally type-queries work like this:

const user = { name: "Patrick", age: 17 };
let typeofUser: typeof user;

In the example above the "typeofUser" would have the the type:

{ name: string, age: number }

So far so good. But I'm trying to get type-queries to work with classes. For example:

class App {
  states = {
    menu: {
      login() {
        console.log("Menu.login");
      }
    },
    game: {
      update() {
        console.log("Game.update");
      }
    }
  };

  constructor() {
    // FAILS => Cannot find name "states"
    const typeofStates: typeof states = {};

    // FAILS => Cannot find name "states"
    const keyofStates: keyof states = "game";
  }
}

My question is: How can I access class members for type-queries, with eighter the "typeof" or "keyof" operator?

Typescript playground sample

3
  • 3
    typeof App.prototype.states and keyof typeof App.prototype.states. Commented Aug 22, 2018 at 12:13
  • 2
    App['states'] and keyof App['states'] Commented Aug 22, 2018 at 12:50
  • Both of these solutions work, may someone of you suggest your answers as an answer to the question, so I can accept them ? Commented Aug 22, 2018 at 14:01

1 Answer 1

2

Thanks to @cartant in the comments. I'm answering this question myself since he did not post his comment as a answer.


To type-query the type of a class member you can use several methods:

  • Access the prototype:

    App.prototype.states
    
  • Access it via a indexer

    App["states"]
    

    A important thing to note is that this and the above method may not work when the member is private or static.

  • The polymorphic this type

    Everything that has a this in Javascript has a "this type" in typescript. This "this" type can be queried like every other index type.

    this["states"]
    

    Note: You may have issues when using this technique when trying to call a function in another context. Also you cannot use the dot operator! You must use the object index operator instead

The this type-query is very useful in combination with class-inheritance

If you were to Programm a Statemachine for example you could have a abstract "Statemachine" Class and use the this-type-query to get the type of a property in the child class

This may look like this:

abstract class Statemachine {
  /* The typescript compiler won't actually infer "object" but 
    {
       menu: { 
         login() => void
       },
       game: {
         update() => void 
       }
    }

    > In case of the example below! 
  */
  abstract states: object

  getState<K extends keyof this["states"]>(name: K): T[K] {
    return this.states[name];
  }
}

class Game extends Statemachine {
  private states = {
     menu: {
       login() {
         console.log("Menu.login")
       }
     },
     game: {
       update() {
         console.log("Game.update") }
      }
   }
}

const game = new Game()

// Compiler error
game.getState("not a key of game.states")

// Works and intellisense for login()
game.getState("menu")

Reference: https://www.typescriptlang.org/docs/handbook/advanced-types.html Look for polymorphic this.

I hope the code actually works Im on vacation and had no chance to check it...

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.