@@ -294,7 +294,7 @@ function pluck(o, names) {
294
294
}
295
295
```
296
296
297
- Here's how you would write and use this function in TypeScript:
297
+ Here's how you would write and use this function in TypeScript, using the ** index type query ** and ** indexed access ** operators :
298
298
299
299
``` ts
300
300
function pluck<T , K extends keyof T >(o : T , names : K []): T [K ][] {
@@ -311,7 +311,7 @@ let strings: string[] = pluck(person, ['name']); // ok, string[]
311
311
312
312
The compiler checks that ` name ` is actually a property on ` Person ` , and it knows that ` strings ` is a ` string[] ` because ` name ` is a ` string ` .
313
313
To make this work, the example introduces a couple of new type operators.
314
- First is ` keyof T ` , the index type query operator.
314
+ First is ` keyof T ` , the ** index type query operator** .
315
315
For any type ` T ` , ` keyof T ` is the union of known, public property names of ` T ` .
316
316
For example:
317
317
@@ -328,7 +328,7 @@ That means the compiler will check that you pass the right set of property names
328
328
pluck (person , [' age' , ' unknown' ]); // error, 'unknown' is not in 'name' | 'age'
329
329
```
330
330
331
- The second operator is ` T[K] ` , the indexed access operator.
331
+ The second operator is ` T[K] ` , the ** indexed access operator** .
332
332
Here, the type syntax reflects the expression syntax.
333
333
That means that ` person['name'] ` has the type ` Person['name'] ` &mdash ; which in our example is just ` string ` .
334
334
However, just like index type queries, you can use ` T[K] ` in a generic context, which is where its real power comes to life.
@@ -384,7 +384,7 @@ interface PersonReadonly {
384
384
}
385
385
```
386
386
387
- This happens often enough in Javascript that TypeScript provides a way to create new types based on old types &mdash ; mapped types.
387
+ This happens often enough in Javascript that TypeScript provides a way to create new types based on old types &mdash ; ** mapped types** .
388
388
In a mapped type, the new type transforms each property in the old type in the same way.
389
389
For example, you can make all properties of a type ` readonly ` or optional.
390
390
Here are a couple of examples:
@@ -473,6 +473,29 @@ type Record<K extends string | number, T> = {
473
473
}
474
474
` ` `
475
475
476
+ ## Inference from mapped types
477
+
478
+ Now that you know how to wrap the properties of a type, the next thing you'll want to do is unwrap them.
479
+ Fortunately, that's pretty easy:
480
+
481
+ ` ` ` ts
482
+ function unproxify<T >(t : Proxify <T >): T {
483
+ let result = {} as T ;
484
+ for (const k in t ) {
485
+ result [k ] = t [k ].get ();
486
+ }
487
+ return result ;
488
+ }
489
+
490
+ let originalProps = unproxify (proxyProps );
491
+ ```
492
+
493
+ Note that this unwrapping inference works best on * homomorphic* mapped types.
494
+ Homomorphic mapped types are mapped types that iterate over every property of some type, and only those properties: ` { [P in keyof T]: X } ` .
495
+ In the examples above, ` Nullable ` and ` Partial ` are homomorphic whereas ` Pick ` and ` Record ` are not.
496
+ 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 ` .
497
+ If the mapped type is not homomorphic you might have to explicitly give a type parameter to your unwrapping function.
498
+
476
499
# Type Aliases
477
500
478
501
Type aliases create a new name for a type.
0 commit comments