0
type KnownKeys<T> = {
  [K in keyof T]: string extends K ? never : number extends K ? never : K;
} extends { [_ in keyof T]: infer U }
  ? U
  : never;

I feel confused with this type. I cannot understand it. It seams filter all string literal props as an union type. Since

declare let a: KnownKeys<{ test: 34, 23: 'test' }>
a = 'test' // Done.
// a = 23 Error.
// a = '23' Error.

How does it achieves this?

Luciens
  • 338
  • 1
  • 11

1 Answers1

1

My strong guess is that purpose of KnownKeys is to get all explicit or "known" keys from a hybrid type with both hard-coded properties and index signature (see this post for more info and type credit).

KnownKeys has no effect on a type without index signature:

type T11 = KnownKeys<{ test: 34, 23: 'test'}> // "test" | 23
type T12 = keyof { test: 34, 23: 'test'} // same as above

But with a hybrid type, there is a difference:

type T21 = KnownKeys<{ [K: string]: number, foo: number }> // here we can extract "foo" 
type T22 = keyof { [K: string]: number, foo: number } // string | number, this is not so useful...

It works, because a mapped type returns both the index signature and explicit properties:

type T3 = {[K in keyof { [K: string]: number, foo: number }]: number}
// { [x: string]: number; foo: number; } returns signature and "foo" property

So we can assign a never value to the signature part [x: string]: number with the type expression string extends K ? never : number extends K ? never : K. And just filter out all properties with never value by extends { [_ in keyof T]: infer U } ? U : never;. Code

ford04
  • 66,267
  • 20
  • 199
  • 171
  • So, the index signature is also regarded as a 'prop'. Disable this prop does not affect other literal prop declaration. – Luciens Dec 30 '19 at 02:13
  • yeah kinda, if you want to see it this way. And instead of "disabling" the signature, I would rather consider it as creating a new type from a hybrid type. In the hybrid type, props have to conform to the signature as usual. – ford04 Dec 30 '19 at 10:14
  • A new type based on the current type. Got it. – Luciens Dec 30 '19 at 11:54