-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Description
Using a Homomorphic Mapped Type For Omit
interface Obj {
readonly a: string;
b?: number;
c: boolean;
}
// "homomorphic" - preserves all modifiers in BoxedObj
type Boxify<T> = {
[K in keyof T]: { value: T[K] }
}
type BoxedObj = Boxify<Obj>;
// non-"homomorphic" - loses information for BoxedObj2
type Boxify2<Keys extends keyof Obj> = {
[K in Keys]: { value: Obj[K] }
}
type BoxedObj2 = Boxify2<keyof Obj>;-
Today,
Omitis non-homomorphic. Will not preserve shape.- Why?
keyofon its own does not retain its source type.
-
Today, we can write
Omitwith anasclause withExclude- still considered "homomorphic" (even though at this point "homomorphic" is a misnomer).type Omit<T, DroppedKeys extends PropertyKey> = { [K in keyof T as Exclude<K, DroppedKeys>]: T[K] };
-
Switching
Omitat this point would likely be breaky.- Existing code where
interfaces extends fromOmit
- Existing code where
-
Using a "homomorphic"
Omitmakes code flow work better because it can produce union types. -
Could choose to have
Omit(original) andMappedOmit- orOmit(improved) andLegacyOmit.- Swapping
Omitto the "better" version is breaky - at least one package breaks.
- Swapping
-
We really don't want to have 2
Omits, and want to push on an improvedOmit.- Existing code can write
Pick<T, Omit<keyof T, DroppedKeys>>
- Existing code can write
-
Wait, should
Pickbe fixed to use a homomorphic mapped type too?- OH NOOOOOOOOOOOOOOOOOOOOOOOOOOOO
- Almost had a slam dunk on just fixing
Omit.
-
If you fix
Pick, thenOmitdefined asPick<T, Exclude<keyof T, DroppedKeys>>is also homomorphic, right?- Almost - but
Omitis not going to distribute, when we writeExclude<keyof T, DroppedKeys>
- Almost - but
-
So each of them need to be written as their own mapped types written in terms of
keyof T. -
Note: the
asclause forPickshould use an intersection, notExtract- Why?
- Intersections are much faster for unions of literals.
- What's the difference in the general case?
- For literal types, they're the same.
- For object types and generic types, intersections combine and don't always "eradicate" other types to
never.
- Why?