To achieve this, you can leverage the power of mapped types:
type SomeInterface = { tag: 'SomeInterface' }
type SomeOtherInterface = { tag: 'SomeOtherInterface' }
interface Obj {
string1: string
string2: string
array1: SomeInterface[]
array2: SomeOtherInterface[]
}
type ObtainKeys<Obj, Type> = {
[Prop in keyof Obj]: Obj[Prop] extends Type ? Prop : never
}[keyof Obj]
type GetArrayKeys = ObtainKeys<Obj, Array<any>> // "array1" | "array2"
type GetStringKeys = ObtainKeys<Obj, string> // "string1" | "string2"
Interactive Example
ObtainKeys
is a versatile function that takes two arguments. The first argument is the object to check, and the second argument is the type to extract.
The line:
[Prop in keyof Obj]: Obj[Prop] extends Type ? Prop : never
loops through all keys of the
Obj
and evaluates if
Obj[Prop]
matches the specified type. If it does, return
Prop
; otherwise, return
never
.
Utilizing [keyof Obj]
allows us to consolidate all values of our iterated type, as the desired Prop
resides in the value position. The union operation with never
ensures we retain the original type without unwanted never
values.