Skip to content

Commit 99e93c1

Browse files
committed
win(добавление): add 4.8@beta
add 4.8@beta
1 parent 8983756 commit 99e93c1

File tree

9 files changed

+347
-0
lines changed
  • what-is-new/4.8
    • [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Неограниченные генерики больше не совместимы с {}
    • [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Типы больше не могут быть импортированы и экспортированы в JavaScript файлах
    • metadata
    • Возникновение ошибки при проверке на равенство с литералом объектного типа
    • Ужесточение правил вывода типов
    • Улучшение вывода для infer в литеральных строковых типах
    • Улучшение пересечений, объединений и механизма сужения типов
    • Улучшение производительности для флагов --build, --watch и --incremental

9 files changed

+347
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
## [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Неограниченные генерики больше не совместимы с {}
2+
3+
До этого неограниченные параметры типа были совместимы с типом `{}`.
4+
5+
`````ts
6+
function f<T> ( p: T ) {
7+
let a: {} = p; // (раньше) Ok
8+
}
9+
`````
10+
11+
Это поведение было причиной возникновения различного рода казусов.
12+
13+
`````ts
14+
function toKeys ( object: {} ) {
15+
Object.keys( object );
16+
}
17+
18+
function f<T> ( p: T ) {
19+
let keys = toKeys( p ) // (раньше) Ok, но ошибка вовремя выполнения программы поскольку в функцию toKeys может
20+
// попасть undefined
21+
}
22+
23+
f( undefined ); // ломаем программу передав undefined
24+
`````
25+
26+
В связи с этим поведение было изменено.
27+
28+
`````ts
29+
function f<T> ( p: T ) {
30+
let a: {} = p; // (раньше) Ok (теперь) Error -> Type 'T' is not assignable to type '{}'.(2322)
31+
}
32+
`````
33+
34+
Для сохранения логики при новом поведении необходимо явно ограничить параметр типа..
35+
36+
`````ts
37+
function f<T extends {}> ( p: T ) {
38+
let a: {} = p; // (раньше) Ok (теперь) Ok
39+
}
40+
`````
41+
42+
..не допустить принадлежность к `null` или `undefined` при помощи условия..
43+
44+
`````ts
45+
function f<T> ( p: T ) {
46+
if( p === null || p === undefined ){
47+
return;
48+
}
49+
50+
let a: {} = p; // (раньше) Ok (теперь) Ok
51+
}
52+
`````
53+
..или в случае уверенности в наличии значения прибегнуть к помощи ненулевого утверждения (`x!`).
54+
55+
`````ts
56+
function toKeys ( object: {} ) {
57+
Object.keys( object );
58+
}
59+
60+
function f<T> ( p: T ) {
61+
let keys = toKeys( p! ) // (раньше) Ok (теперь) Ok
62+
}
63+
`````
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Типы больше не могут быть импортированы и экспортированы в JavaScript файлах
2+
3+
До этого момента компилятор _TypeScript_ справлялся с компиляцией файлов _JavaScript_ в которых выполнялся импори или экспорт типов не имеющих реального значения. Поскольку в настоящем _JavaScript_ подобное вызывает ошибку, данное поведение было исправлено.
4+
5+
6+
7+
`````ts
8+
- import { SomeValue, SomeType } from "some-module";
9+
+ import { SomeValue } from "some-module";
10+
11+
/**
12+
- * @type {SomeType}
13+
+ * @type {import("some-module").SomeType}
14+
*/
15+
export const value = SomeValue;
16+
`````
17+
18+
`````ts
19+
/**
20+
* @typedef {string | number} SomeType
21+
*/
22+
23+
+ /**
24+
+ * @typedef {SomeType} SomeTypeExported
25+
+ */
26+
- export { SomeType as SomeTypeExported };
27+
`````
28+

what-is-new/4.8/metadata/cover.png

11.3 KB
Loading
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"releaseHistory": [
3+
{
4+
"version": "4.8@beta",
5+
"dateRelease": "June 21, 2022",
6+
"datePublication": "April 26, 2022"
7+
}
8+
],
9+
"colors": {
10+
"bookCoverColors": {
11+
"--color_light":"#dee755",
12+
"--color_middle-lite":"#ffffff",
13+
"--color_accent":"#82ff7a",
14+
"--color_ambient":"#00b6b6"
15+
},
16+
"bookUpdateCurrentVersionCoverColors": {
17+
"--color": "#265589"
18+
}
19+
},
20+
"innovations": [
21+
{
22+
"id": "",
23+
"version": "4.8@beta",
24+
"innovationName": "Улучшение пересечений, объединений и механизма сужения типов",
25+
"dateRelease": "June 21, 2022",
26+
"datePublication": "Jul 12, 2022",
27+
"tags": ["Улучшение"]
28+
},
29+
{
30+
"id": "",
31+
"version": "4.8@beta",
32+
"innovationName": "Улучшение вывода для infer в литеральных строковых типах",
33+
"dateRelease": "June 21, 2022",
34+
"datePublication": "Jul 12, 2022",
35+
"tags": ["Улучшение"]
36+
},
37+
{
38+
"id": "",
39+
"version": "4.8@beta",
40+
"innovationName": "Улучшение производительности для флагов --build, --watch и --incremental",
41+
"dateRelease": "June 21, 2022",
42+
"datePublication": "Jul 12, 2022",
43+
"tags": ["Улучшение"]
44+
},
45+
{
46+
"id": "",
47+
"version": "4.8@beta",
48+
"innovationName": "Возникновение ошибки при проверке на равенство с литералом объектного типа",
49+
"dateRelease": "June 21, 2022",
50+
"datePublication": "Jul 12, 2022",
51+
"tags": ["Изменение"]
52+
},
53+
{
54+
"id": "",
55+
"version": "4.8@beta",
56+
"innovationName": "Ужесточение правил вывода типов",
57+
"dateRelease": "June 21, 2022",
58+
"datePublication": "Jul 12, 2022",
59+
"tags": ["Изменение"]
60+
},
61+
{
62+
"id": "",
63+
"version": "4.8@beta",
64+
"innovationName": "[КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Неограниченные генерики больше не совместимы с {}",
65+
"dateRelease": "June 21, 2022",
66+
"datePublication": "Jul 12, 2022",
67+
"tags": ["Критическое изменение"]
68+
},
69+
{
70+
"id": "",
71+
"version": "4.8@beta",
72+
"innovationName": "## [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Типы больше не могут быть импортированы и экспортированы в JavaScript файлах",
73+
"dateRelease": "June 21, 2022",
74+
"datePublication": "Jul 12, 2022",
75+
"tags": ["Критическое изменение"]
76+
}
77+
]
78+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## Возникновение ошибки при проверке на равенство с литералом объектного типа
2+
3+
В некоторых языках (как например `Phyton`) оператор `==` в операциях с объектными типами выполняет проверку над _значениями_ объектов, как если бы эти объекты были примитивами.
4+
5+
`````py
6+
// выражение проверяет person_array на отсутствие в нем элементов
7+
if person_array == []:
8+
print("Длина массива равна 0!")
9+
`````
10+
11+
В _JavaScript_ объектные типы представлены ссылками на них, поэтому схожее выражение всегда будет ложным. Поэтому, чтобы облегчить новичкам переход из одного языка в _TypeScript_, его поведение было откорректировано.
12+
13+
`````ts
14+
let array: number[] = [];
15+
// бессмысленное условие (раньше) Ok (теперь) Error -> This condition will always return 'false' since JavaScript compares objects by reference, not value.(2839)
16+
if (array === []) {
17+
18+
}
19+
20+
21+
let object: object = {};
22+
// бессмысленное условие (раньше) Ok (теперь) Error -> This condition will always return 'false' since JavaScript compares objects by reference, not value.(2839)
23+
if (object === {}) {
24+
25+
}
26+
`````
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
## Ужесточение правил вывода типов
2+
3+
В некоторых случаях выводу типов приходится выбирать наиболее уместный _шаблон_ своих действий.
4+
5+
`````ts
6+
declare function mergeRandom<T> ( x: T, y: T ): T;
7+
8+
/**
9+
* function mergeRandom<[number, boolean, string]>(x: [number, boolean, string], y: [number, boolean, string]):
10+
* [number, boolean, string]
11+
*
12+
* a: number, b: boolean, c: string
13+
*/
14+
let [a, b, c] = mergeRandom([100, true, `🙂`], [500, false, `🤩`]);
15+
16+
let a0 = [100, true, `🙂`]; // let a0: (string | number | boolean)[]
17+
let a1 = [500, false, `🤩`]; // let a1: (string | number | boolean)[]
18+
19+
/**
20+
* function mergeRandom<(string | number | boolean)[]>(x: (string | number | boolean)[], y: (string | number |
21+
* boolean)[]): (string | number | boolean)[]
22+
*
23+
* d: string | number | boolean, e: string | number | boolean, f: string | number | boolean
24+
*/
25+
let [d, e, f] = mergeRandom( a0, a1 );
26+
`````
27+
28+
Пример выше иллюстрирует, как выводу типов, помимо выбора между принадлежностью к кортежу или массиву, в стлучае с кортежем приходится прибегать к анализу его элементов. В случае неопределенности, как в примере ниже, вывод типов рассматривал элементы, как принадлежащие к типу `any`, что понижало типобезопасность программ.
29+
30+
`````TS
31+
declare function f<T> ( p?: T ): T;
32+
33+
/**
34+
* (раньше) Ok
35+
* [a: any, b: any, c: any] = function f<[any, any, any]>(p?: [any, any, any] | undefined): [any, any, any]
36+
*
37+
* (теперь) Error -> Type 'unknown' must have a '[Symbol.iterator]()' method that returns an iterator.(2488)
38+
*
39+
* function f<unknown>(p?: unknown): unknown
40+
*/
41+
let [a, b, c] = f();
42+
`````
43+
44+
Начиная с текущей версии, вывод типов больше не прибегает к алгоритмам выбора наиболее подходящего паттерна, а вместо этого выбрасывает при подобных сценариях ошибку, принуждающую к более типобезопасному явному указанию типов.
45+
46+
`````ts
47+
declare function f<T> ( p?: T ): T;
48+
49+
let [a, b, c] = f<[number, boolean, string]>(); // a: number, b: boolean, c: string
50+
`````
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
## Улучшение вывода для infer в литеральных строковых типах
2+
3+
Начиная с текущей версии _TypeScript_ анализирует тип переменных типа `infer` определенных в литеральных строковых типах.
4+
5+
`````ts
6+
function f0 ( p: "true" extends `${ infer U extends boolean }` ? U : never ) {
7+
p; // (раньше) boolean (теперь) true
8+
}
9+
function f1 ( p: "100" extends `${ infer U extends number }` ? U : never ) {
10+
p; // (раньше) number (теперь) 100
11+
}
12+
function f2 ( p: "100" extends `${ infer U extends bigint }` ? U : never ) {
13+
p; // (раньше) bigint (теперь) 100n
14+
}
15+
`````
16+
17+
Но есть один нюанс на который стоит обратить внимание. Дело в том, что новый механизм судит о принадлежности типа на основе двухстороннего анализа. То есть, он сначала преобразует значение к указанному типу, а затем преобразует его обратно к первостепенному типу. И если значение полученное в результате преобразования будет отличаться, то тип будет выведен не литеральный. То есть, логическое выражение `String(Boolean("true"")) === "true"` будет верным, а вот `String(Number("1.0")) === "1.0"` нет, поскольку результатом преобразования `String(Number("1.0"))` будет `1`, а не `1.0`.
18+
19+
`````ts
20+
function f ( p: "1.0" extends `${ infer T extends number }` ? T : never ) {
21+
p; // (раньше) number (теперь) number
22+
}
23+
`````
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
## Улучшение пересечений, объединений и механизма сужения типов
2+
3+
Начиная с версии `4.8` _TypeScript_ вносит значительные изменения при работе в строгом режиме (конкретно `--strictNullChecks`) затрагивающие пересечения и объединения, а также механизм их сужения.
4+
5+
Теперь такой тип, как `unknown` стоит воспринимать в образе объединения `{} | null | undefined`, что даже выглядит логичным поскольку он представляет `null`, `undefined` или любой другой тип. Это в свою очередь делает совместимым тип `unknown` с перечисленными типами.
6+
7+
`````ts
8+
function f ( a: unknown, b: {} | null | undefined ) {
9+
a = b; // (раньше) Ok (теперь) Ok
10+
b = a; // (раньше) Error (теперь) Ok
11+
}
12+
`````
13+
14+
Следующее изменение затронуло правило сужения пересечения типа `{}` с другим конкретным типом, в результате чего пересечение сужается до более конкретного типа.
15+
16+
`````ts
17+
class A {
18+
value = true;
19+
}
20+
21+
let a: {} & A; // (раньше) let a: {} & A (теперь) let a: A
22+
let b: {} & string; // (раньше) let b: {} & string (теперь) let b: string
23+
`````
24+
25+
Тем не менее пересечение `{}` с типами `null` или `undefined` сужается до типа `never`.
26+
27+
Этот факт позволил улучшить логику такого типа, как `NonNullable<T>`, который, как все помнят, предназначен для исключения типов `null` и `undefined` из объединений.
28+
29+
`````ts
30+
let v: NonNullable<string | number | null | undefined>; // let v: string | number
31+
`````
32+
33+
`````ts
34+
- type NonNullable<T> = T extends null | undefined ? never : T;
35+
+ type NonNullable<T> = T & {};
36+
`````
37+
38+
Поскольку пересечения `{} & null` и `{} & undefined` сужаются до типа `never`, а объединение `never | ConcreteType` сужаются до конкретного типа, то по факту новая логика `NonNullable<T>` просто отбрасывает из объединения все `null` и `undefined`.
39+
40+
Результатом всего это стало возможным уменьшение условного типа (пока только его) `NonNullable<T>`.
41+
42+
`````ts
43+
function foo<T> ( a: NonNullable<T>, b: NonNullable<NonNullable<T>> ) {
44+
a = b; // (раньше) Ok (теперь) Ok
45+
b = a; // (раньше) Error (теперь) Ok
46+
}
47+
`````
48+
49+
В свою очередь эти изменения позволили улучшить анализ потока управления и сужения типов.
50+
51+
`````ts
52+
function f ( p: unknown ) {
53+
if ( p ) {
54+
// (раньше) unknown (теперь) {}
55+
} else {
56+
// (раньше) unknown (теперь) unknown
57+
}
58+
}
59+
`````
60+
61+
Данное поведение распространяется и на генерики.
62+
63+
`````ts
64+
function nullableAssert<T> ( value: T ): NonNullable<T> {
65+
if ( value === undefined || value === null ) {
66+
throw Error( `Value not must null.` );
67+
}
68+
69+
/**
70+
* (раньше) Error -> Type 'T' is not assignable to type 'NonNullable<T>'.(2322)
71+
* (теперь) Ok
72+
*/
73+
return value;
74+
}
75+
`````
76+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Улучшение производительности для флагов --build, --watch и --incremental
2+
3+
Оптимизация процессов связанных со сборкой у разработчиков _TypeScript_ всегда находится в особом статусе. Поэтому Начиная с текущей версии сборка будет происходить на `10-25%` быстрее.

0 commit comments

Comments
 (0)