I have an undetermined number of objects in a key-value parent object. Each child has a property namespaced
of type boolean
:
const obj1 = {
namespaced: true,
a() {}
} as const
const obj2 = {
namespaced: false,
b() {}
} as const
const parentObj = {
obj1,
obj2
} as const
Is it possible to make a mapped type which contains only objects with namespaced
set to true
(and the same with false
)?
interface ParentObj {
[name: string]: Obj
}
interface Obj {
namespaced: boolean
}
type FilterNamespaced<P extends ParentObj> = {
[O in keyof P]: P[O] extends { namespaced: true } ? P[O] : never
}
type FilterNotNamespaced<P extends ParentObj> = {
[O in keyof P]: P[O] extends { namespaced: false } ? P[O] : never
}
type F1 = FilterNamespaced<typeof parentObj>
type F2 = FilterNotNamespaced<typeof parentObj>
It is almost done but F1
still contains a key obj2
of type never, and F2
contains a key obj1
too. I would like to have the same thing but without these keys.
You can do it, but you need an extra level of indirection. You need to filter the keys first and then pick them from the original type. Using something like KeyOfType
from here will get you to where you want:
type KeyOfType<T, U> = { [P in keyof T]: T[P] extends U ? P : never }[keyof T]
type FilterNamespaced<P extends ParentObj> = Pick<P, KeyOfType<P, { namespaced: true }>>
type FilterNotNamespaced<P extends ParentObj> = Pick<P, KeyOfType<P, { namespaced: false }>>