-
Notifications
You must be signed in to change notification settings - Fork 1.1k
More discussion of homomorphic mapped types #473
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -834,6 +834,10 @@ type Partial<T> = { [P in keyof T]?: T[P] } | |
|
||
In these examples, the properties list is `keyof T` and the resulting type is some variant of `T[P]`. | ||
This is a good template for any general use of mapped types. | ||
That's because this kind of transformation is homomorphic, which means that the mapping applies to every property of `T` and no others. | ||
The compiler knows that it can copy all the existing property modifiers before adding any new ones. | ||
For example, if `Person.name` were readonly, `Partial<Person>.name` would be readonly and optional. | ||
|
||
Here's one more example, in which `T[P]` is wrapped in a `Proxy<T>` class: | ||
|
||
```ts | ||
|
@@ -861,6 +865,16 @@ type Record<K extends string | number, T> = { | |
} | ||
``` | ||
|
||
`Readonly` and `Partial` are homomorphic whereas `Pick` and `Record` are not. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that is not accurate, Pick is homorophic, since it is declared as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To be clear a homomorphic type is one of the form: type H1<T> = { [P in keyof T] ... };
type H2<T, K extends keyof T> = { [P in K] ... }; basically any way for the type system to know that the mapped type is a transfomration on another type. type H3<T, K extends string> = { [P in K]: Op<T> }; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice catch. I forgot about that change. Updated. |
||
One clue that `Pick` and `Record` are not homomorphic is that they both take a union of property names: | ||
|
||
```ts | ||
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string> | ||
type PersonJustName = Pick<Person, 'name'>; | ||
``` | ||
|
||
These non-homomorphic types are essentially creating new properties (even though `Pick` uses `Person` as a source), so they don't copy property modifiers from anywhere; if `Person.name` were readonly, `Pick<Person, 'name'>.name` would not be readonly. | ||
|
||
## Inference from mapped types | ||
|
||
Now that you know how to wrap the properties of a type, the next thing you'll want to do is unwrap them. | ||
|
@@ -878,8 +892,5 @@ function unproxify<T>(t: Proxify<T>): T { | |
let originalProps = unproxify(proxyProps); | ||
``` | ||
|
||
Note that this unwrapping inference works best on *homomorphic* mapped types. | ||
Homomorphic mapped types are mapped types that iterate over every property of some type, and only those properties: `{ [P in keyof T]: X }`. | ||
In the examples above, `Nullable` and `Partial` are homomorphic whereas `Pick` and `Record` are not. | ||
One clue is that `Pick` and `Record` both take a union of property names in addition to a source type, which they use instead of `keyof T`. | ||
Note that this unwrapping inference works best on homomorphic mapped types. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll fix the discussion. |
||
If the mapped type is not homomorphic you might have to explicitly give a type parameter to your unwrapping function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
might be useful to add a link to wikipedia's definition of Homomorphism: https://en.wikipedia.org/wiki/Homomorphism
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done