Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit ae6832a

Browse files
authored
Merge pull request #473 from Microsoft/homomorphic-mapped-types
More discussion of homomorphic mapped types
2 parents eaeafbe + 4698ce4 commit ae6832a

File tree

1 file changed

+15
-5
lines changed

1 file changed

+15
-5
lines changed

pages/Advanced Types.md

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,10 @@ type Partial<T> = { [P in keyof T]?: T[P] }
834834
835835
In these examples, the properties list is `keyof T` and the resulting type is some variant of `T[P]`.
836836
This is a good template for any general use of mapped types.
837+
That's because this kind of transformation is [homomorphic](https://en.wikipedia.org/wiki/Homomorphism), which means that the mapping applies only to properties of `T` and no others.
838+
The compiler knows that it can copy all the existing property modifiers before adding any new ones.
839+
For example, if `Person.name` were readonly, `Partial<Person>.name` would be readonly and optional.
840+
837841
Here's one more example, in which `T[P]` is wrapped in a `Proxy<T>` class:
838842
839843
```ts
@@ -861,6 +865,15 @@ type Record<K extends string | number, T> = {
861865
}
862866
```
863867
868+
`Readonly`, `Partial` and `Pick` are homomorphic whereas `Record` is not.
869+
One clue that `Record` is not homomorphic is that it doesn't take an input type to copy properties from:
870+
871+
```ts
872+
type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string>
873+
```
874+
875+
Non-homomorphic types are essentially creating new properties, so they can't copy property modifiers from anywhere.
876+
864877
## Inference from mapped types
865878
866879
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 +891,5 @@ function unproxify<T>(t: Proxify<T>): T {
878891
let originalProps = unproxify(proxyProps);
879892
```
880893

881-
Note that this unwrapping inference works best on *homomorphic* mapped types.
882-
Homomorphic mapped types are mapped types that iterate over every property of some type, and only those properties: `{ [P in keyof T]: X }`.
883-
In the examples above, `Nullable` and `Partial` are homomorphic whereas `Pick` and `Record` are not.
884-
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`.
885-
If the mapped type is not homomorphic you might have to explicitly give a type parameter to your unwrapping function.
894+
Note that this unwrapping inference only works on homomorphic mapped types.
895+
If the mapped type is not homomorphic you'll have to give an explicit type parameter to your unwrapping function.

0 commit comments

Comments
 (0)