0

I have a Market class which has only 1 parameter: name.

class Market {
  name: string

  constructor(name: string) {
    this.name = name
  }
}

I then have a Markets class which is a static collection of several markets.

class Markets {
  static M1 = new Market("M1M")
  static M2 = new Market("M2M")
  static M3 = new Market("M3M")
}

I was wondering if there was a way to extract all name parameters from all markets into a type, such that the type would look something like this:

type MarketNames = "M1M" | "M2M" | "M3M"

I know about the keyof operator, is it the way?

Thanks.

Riccardo Perego
  • 383
  • 1
  • 11
  • [TS keys of type](https://stackoverflow.com/questions/54520676/in-typescript-how-to-get-the-keys-of-an-object-type-whose-values-are-of-a-given). – kelsny Sep 28 '22 at 20:34
  • @caTS I have read it, but don't know how to apply it in order to get the value. – Riccardo Perego Sep 28 '22 at 20:35
  • @caTS In the answer you've attached he is trying to get the keys whilst I'm trying to get the values. – Riccardo Perego Sep 28 '22 at 20:38
  • Ah... I did not read that closely. I assumed you got the result from the key names... – kelsny Sep 28 '22 at 20:42
  • @Riccardo You're not just trying to get the values, you're trying to get the parameters used to instantiate the static values. That's much more difficult, and doesn't line up with the title of the question. (I'd call it impossible _unless_ you change the definition of Market to be generic based on the string literal passed in, and at that point I think it makes sense to define the constants elsewhere and programmatically create the static members.) – Jeff Bowman Sep 28 '22 at 20:42
  • @JeffBowman You reckon I'm just better off manually listing the type through string union? – Riccardo Perego Sep 28 '22 at 20:46

1 Answers1

1

For this to work, your class has to be generic, so we can "extract" the generic out of it later:

class Market<Name extends string> {
  name: Name;

  constructor(name: Name) {
    this.name = name
  }
}

Then we create our type to extract the names:

type NamesOfMarkets<T> = Extract<T[keyof T], Market<string>> extends Market<infer N> ? N : never;

We're filtering out the values of the class for only Markets, then we infer the name and return that.

Note: you must pass the class as typeof Markets to get the constructor type. Markets by itself is simply a class instance.

Playground

kelsny
  • 23,009
  • 3
  • 19
  • 48
  • Thanks! Just checked your GitHub. Where did you learn types so well? Do you have any resource to suggest? – Riccardo Perego Sep 28 '22 at 20:56
  • You pick up a few things when using a language for some time. I didn't really use any resources, but I found a really good one that is unfortunately a work-in-progress: https://type-level-typescript.com/. Also check out [Typescript Deep Dive](https://basarat.gitbook.io/typescript/). – kelsny Sep 28 '22 at 20:57
  • Last clarification, what is the purpose of typeof Markets? To gain access to the static methods? – Riccardo Perego Sep 28 '22 at 21:50
  • Yes, basically. – kelsny Sep 28 '22 at 22:02