How to get a subset of `keyof T` whose value, T[K] are callable functions in Typescript

后端 未结 1 2060
北海茫月
北海茫月 2020-11-28 16:43

I want to filter keyof T based on type of T[keyof T]

It should work like this:

type KeyOfType = ...

KeyOfType&         


        
相关标签:
1条回答
  • 2020-11-28 17:11

    You can do this using conditional and mapped types

    type KeyOfType<T, U> = {[P in keyof T]: T[P] extends U ? P: never}[keyof T]
    

    Let's break things down a little bit.

    We can start with a mapped type, that has the same properties of the same type as the original T, this a simple standard mapped type:

    type KeyOfType<T> = { [P in keyof T]: T[P] } // New Type same as the original
    

    T[P] is a type query and means the type of the key P in type T. We can change this to just P, meaning that the type of the new property is the same as it's name:

    type KeyOfType<T> = { [P in keyof T]: P }
    // So
    KeyOfType<{ a: number, b: string }> == { a: 'a', b: 'b' }
    

    We can add a type query to this type to again get all the keys of the type. Generally a construct T[keyof T] gets all the property types of a type. Applying this to our mapped type which has the property types the same as the key names we basically get back to keyof T:

    type KeyOfType<T> = { [P in keyof T]: P }[keyof T]
    // So
    KeyOfType<{ a: number, b: string }> ==  'a'|'b' 
    

    Now we can add a conditional type to o not always select P. Since A | never == A we can set the type of the property in the mapped type to never if the type of the original property (T[P]) does not meet a certain constraint.

    To express the constraint we add an extra generic parameter U and we use a conditional type which has the form T extends U ? TypeIfTrue: TYpeIfFalse. Putting it together we get:

    type KeyOfType<T, U> = {[P in keyof T]: T[P] extends U ? P: never}[keyof T]
    
    0 讨论(0)
提交回复
热议问题