diff --git a/pages/Advanced Types.md b/pages/Advanced Types.md index 981b900a9..c289c7434 100644 --- a/pages/Advanced Types.md +++ b/pages/Advanced Types.md @@ -834,6 +834,10 @@ type Partial = { [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](https://en.wikipedia.org/wiki/Homomorphism), which means that the mapping applies only to properties 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.name` would be readonly and optional. + Here's one more example, in which `T[P]` is wrapped in a `Proxy` class: ```ts @@ -861,6 +865,15 @@ type Record = { } ``` +`Readonly`, `Partial` and `Pick` are homomorphic whereas `Record` is not. +One clue that `Record` is not homomorphic is that it doesn't take an input type to copy properties from: + +```ts +type ThreeStringProps = Record<'prop1' | 'prop2' | 'prop3', string> +``` + +Non-homomorphic types are essentially creating new properties, so they can't copy property modifiers from anywhere. + ## 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 +891,5 @@ function unproxify(t: Proxify): 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`. -If the mapped type is not homomorphic you might have to explicitly give a type parameter to your unwrapping function. +Note that this unwrapping inference only works on homomorphic mapped types. +If the mapped type is not homomorphic you'll have to give an explicit type parameter to your unwrapping function.