Skip to content

Commit 11b39e0

Browse files
authored
Sync (#1)
* Add release notes * Remove headers * Add links to documentation for @types, --types and --typeRoots Referenced in microsoft/TypeScript#11437 (comment) * Update Compiler Options.md Fix minor typo. * Mention Babel at top of Gulp tutorial. * IntelliJ Mac for nightly builds Maybe include IntelliJ IDEA IDE for mac, too? * Updated whitespaces and empty lines * Use 'awesome-typescript-loader', use SFCs. * Mentioned support for --outFile together with AMD or System * Fixed broken link in React Webpack tutorial Updated the path reference to the page about tsconfig.json as it was broken. * Fixes microsoft#420 clarifies Do's and Don'ts Use Optional Parameters section See https://gist.github.com/agrberg/7bf64c61d3c6de0c638e7c0bc4742000 for more details * Change </br> to <br/> * Fix microsoft/TypeScript#10433 * Fix microsoft/vscode#14322 * Fix paths example: target should be "jquery", not "jquery.d.ts" Also add missing closing braces and have all json consistently use 2 space indents. * Port fix in microsoft#432 * Fix lint failure * Fixed typo * Invoke origin setter in Decorators.md * Add object rest/spread * Update compiler options for TS 2.1 * Review comments * Fix microsoft#348 * Review comments * Add TypeScript 2.1 release notes * Reorder * Fix typo * Minor typo * Document index and indexed access types * Document mapped types * Reword and reorder index types discussion * Fix module import * Grammar fix * Review comments * Simplify keyof * Fix typos * Reorder mapped types example Based on the more involved discussion from the blog post. * Minor edits from PR comments * Discuss mapped type inference and call out terms better * Move index and map types to end of Advanced Types The feature depends on type aliases and string literal types, so should come after those. * Document [non-]nullable types * Does not require `this.` before props in the stateless functional component example * `Hello` must be exported to be used in `index.tsx` * Removed typo square bracket * Minor formatting tweak from PR comments * Mention there are currently 2 webpack loaders for typescript and link to more information Fixes microsoft#450 * Fix defaults for `--importHelpers` * Add breaking change link to release-notes * Fix typo in variable reference * Fix two small errors in React + Webpack tutorial. * fixing #12872, add a mistype to show the usage of optional properties * Fix typos * Change the phrasing on webpack typescript loaders to be more clear * Update Interfaces.md * Update Interfaces.md * limit files to just the src directory * Update 'include' in React guide.
1 parent 1dc06e6 commit 11b39e0

26 files changed

+3956
-111
lines changed

pages/Advanced Types.md

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,108 @@ The right side of the `instanceof` needs to be a constructor function, and TypeS
283283

284284
in that order.
285285

286+
# Nullable types
287+
288+
TypeScript has two special types, `null` and `undefined`, that have the values null and undefined respectively.
289+
We mentioned these briefly in [the Basic Types section](./Basic Types.md).
290+
By default, the type checker considers `null` and `undefined` assignable to anything.
291+
Effectively, `null` and `undefined` are valid values of every type.
292+
That means it's not possible to *stop* them from being assigned to any type, even when you would like to prevent it.
293+
The inventor of `null`, Tony Hoare, calls this his ["billion dollar mistake"](https://en.wikipedia.org/wiki/Null_pointer#History).
294+
295+
The `--strictNullChecks` flag fixes this: when you declare a variable, it doesn't automatically include `null` or `undefined`.
296+
You can include them explicitly using a union type:
297+
298+
```ts
299+
let s = "foo";
300+
s = null; // error, 'null' is not assignable to 'string'
301+
let sn: string | null = "bar";
302+
sn = null; // ok
303+
304+
sn = undefined; // error, 'undefined' is not assignable to 'string | null'
305+
```
306+
307+
Note that TypeScript treats `null` and `undefined` differently in order to match JavaScript semantics.
308+
`string | null` is a different type than `string | undefined` and `string | undefined | null`.
309+
310+
## Optional parameters and properties
311+
312+
With `--strictNullChecks`, an optional parameter automatically adds `| undefined`:
313+
314+
```ts
315+
function f(x: number, y?: number) {
316+
return x + (y || 0);
317+
}
318+
f(1, 2);
319+
f(1);
320+
f(1, undefined);
321+
f(1, null); // error, 'null' is not assignable to 'number | undefined'
322+
```
323+
324+
The same is true for optional properties:
325+
326+
```ts
327+
class C {
328+
a: number;
329+
b?: number;
330+
}
331+
let c = new C();
332+
c.a = 12;
333+
c.a = undefined; // error, 'undefined' is not assignable to 'number'
334+
c.b = 13;
335+
c.b = undefined; // ok
336+
c.b = null; // error, 'null' is not assignable to 'number | undefined'
337+
```
338+
339+
## Type guards and type assertions
340+
341+
Since nullable types are implemented with a union, you need to use a type guard to get rid of the `null`.
342+
Fortunately, this is the same code you'd write in JavaScript:
343+
344+
```ts
345+
function f(sn: string | null): string {
346+
if (sn == null) {
347+
return "default";
348+
}
349+
else {
350+
return sn;
351+
}
352+
}
353+
```
354+
355+
The `null` elimination is pretty obvious here, but you can use terser operators too:
356+
357+
```ts
358+
function f(sn: string | null): string {
359+
return sn || "default";
360+
}
361+
```
362+
363+
In cases where the compiler can't eliminate `null` or `undefined`, you can use the type assertion operator to manually remove them.
364+
The syntax is postfix `!`: `identifier!` removes `null` and `undefined` from the type of `identifier`:
365+
366+
```ts
367+
function broken(name: string | null): string {
368+
function postfix(epithet: string) {
369+
return name.charAt(0) + '. the ' + epithet; // error, 'name' is possibly null
370+
}
371+
name = name || "Bob";
372+
return postfix("great");
373+
}
374+
375+
function fixed(name: string | null): string {
376+
function postfix(epithet: string) {
377+
return name!.charAt(0) + '. the ' + epithet; // ok
378+
}
379+
name = name || "Bob";
380+
return postfix("great");
381+
}
382+
```
383+
384+
The example uses a nested function here because the compiler can't eliminate nulls inside a nested function (except immediately-invoked function expressions).
385+
That's because it can't track all calls to the nested function, especially if you return it from the outer function.
386+
Without knowing where the function is called, it can't know what the type of `name` will be at the time the body executes.
387+
286388
# Type Aliases
287389

288390
Type aliases create a new name for a type.
@@ -568,3 +670,216 @@ let v = new ScientificCalculator(2)
568670
Without `this` types, `ScientificCalculator` would not have been able to extend `BasicCalculator` and keep the fluent interface.
569671
`multiply` would have returned `BasicCalculator`, which doesn't have the `sin` method.
570672
However, with `this` types, `multiply` returns `this`, which is `ScientificCalculator` here.
673+
674+
# Index types
675+
676+
With index types, you can get the compiler to check code that uses dynamic property names.
677+
For example, a common Javascript pattern is to pick a subset of properties from an object:
678+
679+
```js
680+
function pluck(o, names) {
681+
return names.map(n => o[n]);
682+
}
683+
```
684+
685+
Here's how you would write and use this function in TypeScript, using the **index type query** and **indexed access** operators:
686+
687+
```ts
688+
function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
689+
return names.map(n => o[n]);
690+
}
691+
692+
interface Person {
693+
name: string;
694+
age: number;
695+
}
696+
let person: Person;
697+
let strings: string[] = pluck(person, ['name']); // ok, string[]
698+
```
699+
700+
The compiler checks that `name` is actually a property on `Person`, and it knows that `strings` is a `string[]` because `name` is a `string`.
701+
To make this work, the example introduces a couple of new type operators.
702+
First is `keyof T`, the **index type query operator**.
703+
For any type `T`, `keyof T` is the union of known, public property names of `T`.
704+
For example:
705+
706+
```ts
707+
let personProps: keyof Person; // 'name' | 'age'
708+
```
709+
710+
`keyof Person` is completely interchangeable with `'name' | 'age'`.
711+
The difference is that if you add another property to `Person`, say `address: string`, then `keyof Person` will automatically update to be `'name' | 'age' | 'address'`.
712+
And you can use `keyof` in generic contexts like `pluck`, where you can't possibly know the property names ahead of time.
713+
That means the compiler will check that you pass the right set of property names to `pluck`:
714+
715+
```ts
716+
pluck(person, ['age', 'unknown']); // error, 'unknown' is not in 'name' | 'age'
717+
```
718+
719+
The second operator is `T[K]`, the **indexed access operator**.
720+
Here, the type syntax reflects the expression syntax.
721+
That means that `person['name']` has the type `Person['name']` &mdash; which in our example is just `string`.
722+
However, just like index type queries, you can use `T[K]` in a generic context, which is where its real power comes to life.
723+
You just have to make sure that the type variable `K extends keyof T`.
724+
Here's another example with a function named `getProperty`.
725+
726+
```ts
727+
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
728+
return o[name]; // o[name] is of type T[K]
729+
}
730+
```
731+
732+
In `getProperty`, `o: T` and `name: K`, so that means `o[name]: T[K]`.
733+
Once you return the T[K] result, the compiler will instantiate the actual type of the key, so the return type of `getProperty` will vary according to which property you request.
734+
735+
```ts
736+
let name: string = getProperty(person, 'name');
737+
let age: number = getProperty(person, 'age');
738+
let unknown = getProperty(person, 'unknown'); // error, 'unknown' is not in 'name' | 'age'
739+
```
740+
741+
## Index types and string index signatures
742+
743+
`keyof` and `T[K]` interact with string index signatures.
744+
If you have a type with a string index signature, `keyof T` will just be `string`.
745+
And `T[string]` is just the type of the index signature:
746+
747+
```ts
748+
interface Map<T> {
749+
[key: string]: T;
750+
}
751+
let keys: keyof Map<number>; // string
752+
let value: Map<number>['foo']; // number
753+
```
754+
755+
# Mapped types
756+
757+
A common task is to take an existing type and make each of its properties optional:
758+
759+
```ts
760+
interface PersonPartial {
761+
name?: string;
762+
age?: number;
763+
}
764+
```
765+
766+
Or we might want a readonly version:
767+
768+
```ts
769+
interface PersonReadonly {
770+
readonly name: string;
771+
readonly age: number;
772+
}
773+
```
774+
775+
This happens often enough in Javascript that TypeScript provides a way to create new types based on old types &mdash; **mapped types**.
776+
In a mapped type, the new type transforms each property in the old type in the same way.
777+
For example, you can make all properties of a type `readonly` or optional.
778+
Here are a couple of examples:
779+
780+
```ts
781+
type Readonly<T> = {
782+
readonly [P in keyof T]: T[P];
783+
}
784+
type Partial<T> = {
785+
[P in keyof T]?: T[P];
786+
}
787+
```
788+
789+
And to use it:
790+
791+
```ts
792+
type PersonPartial = Partial<Person>;
793+
type ReadonlyPerson = Readonly<Person>;
794+
```
795+
796+
Let's take a look at the simplest mapped type and its parts:
797+
798+
```ts
799+
type Keys = 'option1' | 'option2';
800+
type Flags = { [K in Keys]: boolean };
801+
```
802+
803+
The syntax resembles the syntax for index signatures with a `for .. in` inside.
804+
There are three parts:
805+
806+
1. The type variable `K`, which gets bound to each property in turn.
807+
2. The string literal union `Keys`, which contains the names of properties to iterate over.
808+
3. The resulting type of the property.
809+
810+
In this simple example, `Keys` is a hard-coded list of property names and the property type is always `boolean`, so this mapped type is equivalent to writing:
811+
812+
```ts
813+
type Flags = {
814+
option1: boolean;
815+
option2: boolean;
816+
}
817+
```
818+
819+
Real applications, however, look like `Readonly` or `Partial` above.
820+
They're based on some existing type, and they transform the fields in some way.
821+
That's where `keyof` and indexed access types come in:
822+
823+
```ts
824+
type NullablePerson = { [P in keyof Person]: Person[P] | null }
825+
type PartialPerson = { [P in keyof Person]?: Person[P] }
826+
```
827+
828+
But it's more useful to have a general version.
829+
830+
```ts
831+
type Nullable<T> = { [P in keyof T]: T[P] | null }
832+
type Partial<T> = { [P in keyof T]?: T[P] }
833+
```
834+
835+
In these examples, the properties list is `keyof T` and the resulting type is some variant of `T[P]`.
836+
This is a good template for any general use of mapped types.
837+
Here's one more example, in which `T[P]` is wrapped in a `Proxy<T>` class:
838+
839+
```ts
840+
type Proxy<T> = {
841+
get(): T;
842+
set(value: T): void;
843+
}
844+
type Proxify<T> = {
845+
[P in keyof T]: Proxy<T[P]>;
846+
}
847+
function proxify<T>(o: T): Proxify<T> {
848+
// ... wrap proxies ...
849+
}
850+
let proxyProps = proxify(props);
851+
```
852+
853+
Note that `Readonly<T>` and `Partial<T>` are so useful, they are included in TypeScript's standard libarary along with `Pick` and `Record`:
854+
855+
```ts
856+
type Pick<T, K extends keyof T> = {
857+
[P in K]: T[P];
858+
}
859+
type Record<K extends string | number, T> = {
860+
[P in K]: T;
861+
}
862+
```
863+
864+
## Inference from mapped types
865+
866+
Now that you know how to wrap the properties of a type, the next thing you'll want to do is unwrap them.
867+
Fortunately, that's pretty easy:
868+
869+
```ts
870+
function unproxify<T>(t: Proxify<T>): T {
871+
let result = {} as T;
872+
for (const k in t) {
873+
result[k] = t[k].get();
874+
}
875+
return result;
876+
}
877+
878+
let originalProps = unproxify(proxyProps);
879+
```
880+
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.

pages/Basic Types.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ Once again, more on union types later on.
214214
# Never
215215

216216
The `never` type represents the type of values that never occur.
217-
For instance, `never` is the return type for a function expression or an arrow function expresssion that always throws an exception or one that never returns;
217+
For instance, `never` is the return type for a function expression or an arrow function expression that always throws an exception or one that never returns;
218218
Variables also acquire the type `never` when narrowed by any type guards that can never be true.
219219

220220
The `never` type is a subtype of, and assignable to, every type; however, *no* type is a subtype of, or assignable to, `never` (except `never` itself).

pages/Classes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Introduction
22

3-
Traditional JavaScript focuses on functions and prototype-based inheritance as the basic means of building up reusable components, but this may feel a bit awkward to programmers more comfortable with an object-oriented approach, where classes inherit functionality and objects are built from these classes.
3+
Traditional JavaScript uses functions and prototype-based inheritance to build up reusable components, but this may feel a bit awkward to programmers more comfortable with an object-oriented approach, where classes inherit functionality and objects are built from these classes.
44
Starting with ECMAScript 2015, also known as ECMAScript 6, JavaScript programmers will be able to build their applications using this object-oriented class-based approach.
55
In TypeScript, we allow developers to use these techniques now, and compile them down to JavaScript that works across all major browsers and platforms, without having to wait for the next version of JavaScript.
66

0 commit comments

Comments
 (0)