6

Title says it all, but an example is best.

interface A {
  key1: string
  key2: string
  key3: number
}

type KeysOfType<O, T> = keyof {
  [K in keyof O]: O[K] extends T ? O[K] : never
}

function test<O,T>(obj: O, key: KeysOfType<O,T>) {
  obj[key] // should only be of type T
}

const aa: A = {
  key1: "1",
  key2: "2",
  key3: 3
}

test<A,string>(aa, "key1") // should be allowed, because key1 should be a string
test<A,string>(aa, "key3") // should NOT be allowed (but is), because key3 should be a number

However, this allows any keyof the interface A. (i.e., both calls above are valid).

Is it possible to do this with typescript?

HelloWorld
  • 605
  • 1
  • 7
  • 22
  • 2
    Does this answer your question? [How to get a subset of \`keyof T\` whose value, T\[K\] are callable functions in Typescript](https://stackoverflow.com/questions/51419176/how-to-get-a-subset-of-keyof-t-whose-value-tk-are-callable-functions-in-typ) – sam256 Oct 08 '20 at 00:28
  • In short yes, your answer is correct. However I was hoping for the typing to work inside the function as well (i.e., obj[key] would be inferred as type T), but it does not. I can see how this isn't possible or supported yet as it's a bit complex. The type system would need to know that `key` was only going to pull out values from `obj` of type `T`. – HelloWorld Oct 08 '20 at 07:44

1 Answers1

16

Change your KeysofType definition to:

type KeysOfType<O, T> = {
  [K in keyof O]: O[K] extends T ? K : never
}[keyof O]

This is explained in detail in this post.

sam256
  • 1,291
  • 5
  • 29