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

Commit ed9477a

Browse files
Added a "What's New" section for TypeScript 2.4.
1 parent a20a04a commit ed9477a

File tree

1 file changed

+166
-0
lines changed

1 file changed

+166
-0
lines changed

pages/release notes/TypeScript 2.4.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# TypeScript 2.4
2+
3+
## Dynamic Import Expressions
4+
5+
Dynamic `import` expressions are a new feature and part of ECMAScript that allows users to asynchronously request a module at any arbitrary point in your program.
6+
7+
This means that you can conditionally and lazily import other modules and libraries.
8+
For example, here's an `async` function that only imports a utility library when it's needed:
9+
10+
```ts
11+
async function getZipFile(name: string, files: File[]): Promise<File> {
12+
const zipUtil = await import('./utils/create-zip-file');
13+
const zipContents = await zipUtil.getContentAsBlob(files);
14+
return new File(zipContents, name);
15+
}
16+
```
17+
18+
Many bundlers have support for automatically splitting output bundles based on these `import` expressions, so consider using this new feature with the `esnext` module target.
19+
20+
## String Enums
21+
22+
TypeScript 2.4 now allows enum members to contain string initializers.
23+
24+
```ts
25+
enum Colors {
26+
Red = "RED",
27+
Green = "GREEN",
28+
Blue = "BLUE",
29+
}
30+
```
31+
32+
The caveat is that string-initialized enums can't be reverse-mapped to get the original enum member name.
33+
In other words, you can't write `Colors["RED"]` to get the string `"Red"`.
34+
35+
## Improved inference for generics
36+
37+
TypeScript 2.4 introduces a few wonderful changes around the way generics are inferred.
38+
39+
### Return types as inference targets
40+
41+
For one, TypeScript can now make inferences for the return type of a call.
42+
This can improve your experience and catch errors.
43+
Something that now works:
44+
45+
```ts
46+
function arrayMap<T, U>(f: (x: T) => U): (a: T[]) => U[] {
47+
return a => a.map(f);
48+
}
49+
50+
const lengths: (a: string[]) => number[] = arrayMap(s => s.length);
51+
```
52+
53+
54+
As an example of new errors you might spot as a result:
55+
56+
```ts
57+
let x: Promise<string> = new Promise(resolve => {
58+
resolve(10);
59+
// ~~ Error!
60+
});
61+
```
62+
63+
### Type parameter inference from contextual types
64+
65+
Prior to TypeScript 2.4, in the following example
66+
67+
```ts
68+
let f: <T>(x: T) => T = y => y;
69+
```
70+
71+
`y` would have the type `any`.
72+
This meant the program would type-check, but you could technically do anything with `y`, such as the following:
73+
74+
```ts
75+
let f: <T>(x: T) => T = y => y() + y.foo.bar;
76+
```
77+
78+
That last example isn't actually type-safe.
79+
80+
In TypeScript 2.4, the function on the right side implicitly *gains* type parameters, and `y` is inferred to have the type of that type-parameter.
81+
82+
If you use `y` in a way that the type parameter's constraint doesn't support, you'll correctly get an error.
83+
In this case, the constraint of `T` was (implicitly) `{}`, so the last example will appropriately fail.
84+
85+
### Stricter checking for generic functions
86+
87+
TypeScript now tries to unify type parameters when comparing two single-signature types.
88+
As a result, you'll get stricter checks when relating two generic signatures, and may catch some bugs.
89+
90+
```ts
91+
type A = <T, U>(x: T, y: U) => [T, U];
92+
type B = <S>(x: S, y: S) => [S, S];
93+
94+
function f(a: A, b: B) {
95+
a = b; // Error
96+
b = a; // Ok
97+
}
98+
```
99+
100+
## Strict contravariance for callback parameters
101+
102+
TypeScript has always compared parameters in a bivariant way.
103+
There are a number of reasons for this, but by-and-large this was not been a huge issue for our users until we saw some of the adverse effects it had with `Promise`s and `Observable`s.
104+
105+
TypeScript 2.4 introduces tightens this up when relating two callback types. For example:
106+
107+
```ts
108+
interface Mappable<T> {
109+
map<U>(f: (x: T) => U): Mappable<U>;
110+
}
111+
112+
declare let a: Mappable<number>;
113+
declare let b: Mappable<string | number>;
114+
115+
a = b;
116+
b = a;
117+
```
118+
119+
Prior to TypeScript 2.4, this example would succeed.
120+
When relating the types of `map`, TypeScript would bidirectionally relate their parameters (i.e. the type of `f`).
121+
When relating each `f`, TypeScript would also bidirectionally relate the type of *those* parameters.
122+
123+
When relating the type of `map` in TS 2.4, the language will check whether each parameter is a callback type, and if so, it will ensure that those parameters are checked in a contravariant manner with respect to the current relation.
124+
125+
In other words, TypeScript now catches the above bug, which may be a breaking change for some users, but will largely be helpful.
126+
127+
## Weak Type Detection
128+
129+
TypeScript 2.4 introduces the concept of "weak types".
130+
Any type that contains nothing but a set of all-optional properties is considered to be *weak*.
131+
For example, this `Options` type is a weak type:
132+
133+
```ts
134+
interface Options {
135+
data?: string,
136+
timeout?: number,
137+
maxRetries?: number,
138+
}
139+
```
140+
141+
In TypeScript 2.4, it's now an error to assign anything to a weak type when there's no overlap in properties.
142+
For example:
143+
144+
```ts
145+
function sendMessage(options: Options) {
146+
// ...
147+
}
148+
149+
const opts = {
150+
payload: "hello world!",
151+
retryOnFail: true,
152+
}
153+
154+
// Error!
155+
sendMessage(opts);
156+
// No overlap between the type of 'opts' and 'Options' itself.
157+
// Maybe we meant to use 'data'/'maxRetries' instead of 'payload'/'retryOnFail'.
158+
```
159+
160+
You can think of this as TypeScript "toughening up" the weak guarantees of these types to catch what would otherwise be silent bugs.
161+
162+
Since this is a breaking change, you may need to know about the workarounds which are the same as those for strict object literal checks:
163+
164+
1. Declare the properties if they really do exist.
165+
2. Add an index signature to the weak type (i.e. `[propName: string]: {}`).
166+
3. Use a type assertion (i.e. `opts as Options`).

0 commit comments

Comments
 (0)