0

Consider following code: palyground

class A {
  private z = 0
}

type K = "z"
type ValidKeys = A[K] extends any ? K : never

Type ValidKeys compiles fine and becomes the same as K only if K is some subset of keys of A. And doesn't compile if I try to add anything else to K like

type K = "z" | "not-a-key"

That's exactly the behavior that I need, but I want to make ValidKeys generic depending on A and K:

type ValidKeys<A, K> = ...

How can I make such type?


Why do I need it?

I'm using mobx and its documentation says:

  1. By default TypeScript will not allow you to annotate private fields. This can be overcome by explicitly passing the relevant private fields as generic argument, like this: makeObservable<MyStore, "privateField" | "privateField2">(this, { privateField: observable, privateField2: observable })

So I need to pass a type containing some private keys to generic function. If I just pass a literal, code will compile after renaming the property and will break at runtime.

So instead of

constructor() {
  makeObservable<Store, "x" | "y">(this, { x: observable, y: false })
}

I want to write

constructor() {
  makeObservable<Store, ValidKeys<Store, "x" | "y">>(this, { x: observable, y: false })
}

so that it would break at compile-time if the key is renamed.

The only way I found is explicitly write a snippet inside of my constructor:

constructor() {
  type ExtraKeys = "x" | "y"
  type _CompilesIfOk_ExtraKeys = Store[ExtraKeys]
  makeObservable<Store, ExtraKeys>(this, { x: observable, y: false })
}

And want to simplify it and move into some helper.

Qwertiy
  • 19,681
  • 15
  • 61
  • 128

1 Answers1

1

I don't think this is possible right now because private members are not enumerable in keyof. And this is exactly why MobX asking you for the keys, because if it was possible then MobX could just check it by itself (like it does with non-private fields).

Yes, it breaks type safety, but nothing you can do about it at this moment (in a generic way).

There is a discussion about that topic on Github: https://github.com/microsoft/TypeScript/issues/22677

Danila
  • 15,606
  • 2
  • 35
  • 67
  • Oh.. I hoped there is some hack for that... Note that I'm asking not to get all private keys, but only to verify whether specified key exists. – Qwertiy Nov 22 '21 at 12:04
  • This is basically the same problem. If you could verify that the key exists then you could list them and vice-versa. – Danila Nov 22 '21 at 12:21
  • Actually not. My solution in the question does verification, but can't be used to get the keys. – Qwertiy Nov 22 '21 at 12:25