Skip to content

Commit dac4ace

Browse files
committed
win(добавление): add 4.7@beta
add 4.7@beta
1 parent 04659d4 commit dac4ace

File tree

14 files changed

+491
-0
lines changed
  • what-is-new/4.7
    • [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Метод readFile класса LanguageServiceHost теперь обязательный
    • [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Параметры типа больше не совместимы с {} в strictNullChecks
    • [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Свойство length у кортежа теперь readonly
    • metadata
    • typeof для #приватных членов
    • Анализ потока управления для вычисляемых свойств
    • Конкретизация ссылки на функцию
    • Модификаторы вариантности параметров типа in и out
    • Настройка разрешения поиска модулей с помощью moduleSuffixes
    • Ограничение infer с помощью extends
    • Поддержка ECMAScript модулей в Node.js
    • Разрешение импорта и экспорта только типа с помощью resolution-mode
    • Улучшение вывода функций

14 files changed

+491
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Метод readFile класса LanguageServiceHost теперь обязательный
2+
3+
Если вы создаете экземпляр класса `LanguageService`, то необходимые ему `LanguageServiceHosts` теперь обязаны реализовывать метод `readFile`.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Параметры типа больше не совместимы с {} в strictNullChecks
2+
3+
Изначально параметры типа рассматривались компилятором, как неявно принадлежащие к типу `{}`, который затем был заменен на `unknown`. В деактивированном режиме `strictNullChecks` эти два типа совместимы, но при активации совместимость пропадает. Это известный факт, но до текущей версии для обратной совместимости компилятор _TypeScript_ пренебрегал им.
4+
5+
6+
`````ts
7+
function f<T>(x: T) {
8+
const a: {} = x; // Ok
9+
}
10+
`````
11+
12+
Начиная с текущей версии данный прореха в безопасности была закрыта.
13+
14+
`````ts
15+
function f<T>(x: T) {
16+
const a: {} = x; // Error -> Type 'T' is not assignable to type '{}'.ts(2322)
17+
}
18+
`````
19+
`````ts
20+
`````ts
21+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## [КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Свойство length у кортежа теперь readonly
2+
3+
Начиная с текущей версии свойство `length` у кортежей стало только для чтения `readonly`.
4+
5+
`````ts
6+
function f(tuple: [boolean, number, string]) {
7+
tuple.length = 0; // Error -> Type '0' is not assignable to type '3'.
8+
}
9+
`````

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

11.3 KB
Loading
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
{
2+
"releaseHistory": [
3+
{
4+
"version": "4.7@beta",
5+
"dateRelease": "April 8, 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.7@beta",
24+
"innovationName": "Модификаторы вариантности параметров типа in и out",
25+
"dateRelease": "April 8, 2022",
26+
"datePublication": "OApril 26, 2022",
27+
"tags": ["Улучшение"]
28+
},
29+
{
30+
"id": "",
31+
"version": "4.7@beta",
32+
"innovationName": "Анализ потока управления для вычисляемых свойств",
33+
"dateRelease": "April 8, 2022",
34+
"datePublication": "OApril 26, 2022",
35+
"tags": ["Улучшение"]
36+
},
37+
{
38+
"id": "",
39+
"version": "4.7@beta",
40+
"innovationName": "Улучшение вывода функций",
41+
"dateRelease": "April 8, 2022",
42+
"datePublication": "OApril 26, 2022",
43+
"tags": ["Улучшение"]
44+
},
45+
{
46+
"id": "",
47+
"version": "4.7@beta",
48+
"innovationName": "Конкретизация ссылки на функцию",
49+
"dateRelease": "April 8, 2022",
50+
"datePublication": "OApril 26, 2022",
51+
"tags": ["Улучшение"]
52+
},
53+
{
54+
"id": "",
55+
"version": "4.7@beta",
56+
"innovationName": "Ограничение infer с помощью extends",
57+
"dateRelease": "April 8, 2022",
58+
"datePublication": "OApril 26, 2022",
59+
"tags": ["Улучшение"]
60+
},
61+
{
62+
"id": "",
63+
"version": "4.7@beta",
64+
"innovationName": "typeof для #приватных членов",
65+
"dateRelease": "April 8, 2022",
66+
"datePublication": "OApril 26, 2022",
67+
"tags": ["Улучшение"]
68+
},
69+
{
70+
"id": "",
71+
"version": "4.7@beta",
72+
"innovationName": "Настройка разрешения поиска модулей с помощью moduleSuffixes",
73+
"dateRelease": "April 8, 2022",
74+
"datePublication": "OApril 26, 2022",
75+
"tags": ["Нововведение"]
76+
},
77+
{
78+
"id": "",
79+
"version": "4.7@beta",
80+
"innovationName": "Разрешение импорта и экспорта только типа с помощью resolution-mode",
81+
"dateRelease": "April 8, 2022",
82+
"datePublication": "OApril 26, 2022",
83+
"tags": ["Улучшение"]
84+
},
85+
{
86+
"id": "",
87+
"version": "4.7@beta",
88+
"innovationName": "Поддержка ECMAScript модулей в Node.js",
89+
"dateRelease": "April 8, 2022",
90+
"datePublication": "OApril 26, 2022",
91+
"tags": ["Улучшение"]
92+
},
93+
{
94+
"id": "",
95+
"version": "4.7@beta",
96+
"innovationName": "[КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Параметры типа больше не совместимы с {} в strictNullChecks",
97+
"dateRelease": "April 8, 2022",
98+
"datePublication": "OApril 26, 2022",
99+
"tags": ["Критическое изменение"]
100+
},
101+
{
102+
"id": "",
103+
"version": "4.7@beta",
104+
"innovationName": "[КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Метод readFile класса LanguageServiceHost теперь обязательный",
105+
"dateRelease": "April 8, 2022",
106+
"datePublication": "OApril 26, 2022",
107+
"tags": ["Критическое изменение"]
108+
},
109+
{
110+
"id": "",
111+
"version": "4.7@beta",
112+
"innovationName": "[КРИТИЧЕСКОЕ ИЗМЕНЕНИЕ] Свойство length у кортежа теперь readonly",
113+
"dateRelease": "April 8, 2022",
114+
"datePublication": "OApril 26, 2022",
115+
"tags": ["Критическое изменение"]
116+
}
117+
]
118+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## typeof для #приватных членов
2+
3+
Начиная с текущей версии стало возможным выполнять запрос типа на приватных полях предусмотренных в _ECMAScript_ спецификации.
4+
5+
`````ts
6+
class Class {
7+
#field = 100;
8+
9+
method(): typeof this.#field {
10+
return this.#field;
11+
}
12+
}
13+
`````
14+
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
## Анализ потока управления для вычисляемых свойств
2+
3+
Предыдущие версии _TypeScript_ прекрасно справлялись с анализом вычисляемых членов объектов идентификаторы которых определялись непосредственно в квадратных скобках `{[id]: type}`.
4+
5+
`````ts
6+
let o = {
7+
[`hundred`]: Math.round(Math.random()) ? 100 : "100"
8+
};
9+
10+
if (typeof o[`hundred`] === "string") {
11+
o[`hundred`].toUpperCase(); // Ok
12+
}else{
13+
o[`hundred`].toFixed(); // Ok
14+
}
15+
`````
16+
17+
Но это не работало при внешнем определении идентификатора.
18+
19+
`````ts
20+
const key = `hundred`;
21+
22+
let o = {
23+
[key]: Math.round(Math.random()) ? 100 : "100"
24+
};
25+
26+
if (typeof o[key] === "string") {
27+
o[key].toUpperCase(); // Error -> Property 'toUpperCase' does not exist on type 'string | number'.
28+
}else{
29+
o[key].toFixed(); // Error -> Property 'toFixed' does not exist on type 'string | number'.
30+
}
31+
`````
32+
33+
Начиная с текущей версии алгоритм анализа был доработан.
34+
35+
`````ts
36+
const key = `hundred`;
37+
38+
let o = {
39+
[key]: Math.round(Math.random()) ? 100 : "100"
40+
};
41+
42+
if (typeof o[key] === "string") {
43+
o[key].toUpperCase(); // Ok
44+
}else{
45+
o[key].toFixed(); // Ok
46+
}
47+
`````
48+
49+
Кроме этого, новые правила сделали возможным выявление забытых инициализаций для вычисляемых членов.
50+
51+
`````ts
52+
/**
53+
* [*]
54+
* До v4.7 (Ok) на этапе компиляции, но (Error) во время выполнения
55+
* Начиная с v4.7 (Error) -> Property '["field"]' has no initializer and is not definitely assigned in the constructor.ts(2564)
56+
*/
57+
58+
class T {
59+
["field"]: string; // [*]
60+
61+
constructor() {
62+
// Забыли инициализировать индексное поле name
63+
}
64+
}
65+
`````
66+
67+
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
## Конкретизация ссылки на функцию
2+
3+
Существуют ситуации при которых обычные конструкции могут быть более общими, чем это требуется.
4+
5+
`````ts
6+
interface Box<T> {
7+
value: T;
8+
}
9+
10+
// функция, которая порождает коробки с любым содержимым
11+
function createBox<T>(value: T): Box<T> {
12+
return {value};
13+
}
14+
`````
15+
16+
До текущей версии конкретизация типа могла бы быть осуществлена с помощью излишнего кода в виде обертки..
17+
18+
`````ts
19+
interface Food{}
20+
21+
// более конкретная функция, которая порождает исключительно коробки с Food
22+
function createFoodBox(value: Food) {
23+
return createBox(value);
24+
}
25+
`````
26+
27+
..или же при помощи псевдонима типа.
28+
29+
`````ts
30+
type FoodBox = (value: Food) => Box<Food>;
31+
32+
// ссылка на более общую функцию createBox, но конкретизированная псевдонимом типа
33+
const createFoodBox: FoodBox = createBox;
34+
`````
35+
36+
Первый вариант немного излишен, а второй слишком громоздкий. Поэтому для разрешения подобных сценариев был добавлен механизм конкретизации непосредственно самой ссылки на порождающий объект.
37+
38+
`````ts
39+
40+
// сохранение ссылки и конкретизация типа одновременно
41+
const createFoodBox = createBox<Food>;
42+
`````
43+
44+
Этот же механизм распространяется на функции-конструкторы..
45+
46+
`````ts
47+
class Box<T> {
48+
constructor(readonly value: T){}
49+
}
50+
51+
const NumberBox = Box<number>;
52+
let a = new NumberBox(5); // Ok
53+
let b = new NumberBox(`5`); // Error -> Argument of type 'string' is not assignable to parameter of type 'number'.ts(2345)
54+
`````
55+
56+
.. в том числе и `Array`, `Map` и `Set`.
57+
`````ts
58+
const NumberMap = Map<string, number>;
59+
let numberMap = new NumberMap();
60+
`````
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
## Модификаторы вариантности параметров типа in и out
2+
3+
Идентификация данных осуществляется при помощи типов и предназначена для предотвращения попадания в операции неподходящих для них значений. Каждая операция имеет свое низкоуровневое описание содержащее, в том числе и тип, к которому должно принадлежать пригодное для неё значение. Сверка типа значения с этим типом называется процессом выявления совместимости. Совместимость осуществляется по правилам вариантности, которые бывают четырех видов. Но прежде, чем рассмотреть каждый из них, ненадолго отвлечемся на _TypeScript_.
4+
Поскольку _TypeScript_ реализует _структурную типизацию_, тип проще всего представить в виде обычного листка бумаги, который может содержать имена (идентификаторы) ассоциированные с какими-либо другими типами. Идентификатор + ассоциированный с ним тип = признак типа. Именно на основе этих признаков и осуществляется процесс выявления совместимости речь о которой пойдет сразу после того освещения ещё одной очень простой темы - иерархии наследования.
5+
Представляя иерархию наследования в голове сразу вырисовывается картина из мира номинативной типизации, что неосознанно выбивает из колеи структурной. Поэтому сразу стоит сосредоточиться на интересующей нас детали - логическом обозначении иерархических отношений. Дело в том, что иерархия направлена сверху вниз, а значит более базовый тип расположен выше, чем его подтип. Таким образом, в логических выражениях представляющих иерархию базовые типы обозначаются, как большие (`>`) по отношению к своим подтипам. И наоборот. То есть, `SuperType > SubType` и `SubType < SuperType`. Но упомяну ещё раз, в структурной типизации нет понятия иерархия наследования, поскольку при сравнении берутся в расчет признаки типов, а не ссылки (`ref`). Но чтобы не забивать особо голову просто возьмем за правило, что тип, который обладает всеми признаками другого типа и кроме этого содержит дополнительные, будет считаться подтипом, а значит, в логических выражениях будет обозначаться меньшим (`<`).
6+
7+
`````ts
8+
interface A {
9+
f0: boolean;
10+
}
11+
interface B {
12+
f0: boolean;
13+
f1: number;
14+
}
15+
interface С {
16+
f0: boolean;
17+
f1: number;
18+
}
19+
20+
// A > B или B < A
21+
// A > C или C < A
22+
// B = C или C = B
23+
`````
24+
25+
Это очень просто и это знают все, но повторить все равно стоило, так как именно логические выражения нам помогут разобраться в количестве видов вариантов совместимости. Теперь, на основе полученной информации давайте рассмотрим варианты по которым может происходить проверка на совместимость.
26+
27+
И так, вариантов всего четыре и каждый из них имеет собственное название. Но чтобы было более понятно рассмотрим сценарий, когда переменной принадлежащей к типу `A` может быть присвоено значение с типом `B`.
28+
29+
`Ковариантность` предполагает, что проверка на совместимость завершится успехом в случаи, когда `B < A` или `B = A` (в номинативной типизации `B` подтип `A` ). `Контрвариантность` предполагает, что `B > A` или `B = A` (в номинативной бы это звучало, как базовый тип можно совместим с подтипом или самим собой, но не наоборот). `Инвариантность`, это когда совместимы исключительно при условии `B = A`. `Бивариантность` подразумевает `B < A`, `B > A` или `B = A`, то есть - все предыдущие варианты в одном.
30+
31+
А теперь к сути дела. В _TypeScript_ все типы проверяются на совместимость по ковариантным правилам, за исключением параметров функций, которые контрвариантны. Поскольку различные правила на сложных рекурсивных типах требуют дорогостоящие вычисления, _TypeScript_ реализует механизм явного аннотирования параметров типа при с помощью необязательных модификаторов `in` и `out`.
32+
33+
`in` указывает, что параметр типа ковариантен, а `out` контрвариантен. Но стоит сделать акцент на том, что с помощью этих модификаторов невозможно изменить правила по которым _TypeScript_ производит вычисления совместимости, а можно лишь их конкретизировать.
34+
35+
`````ts
36+
type Setter<T> = (param: T) => void;
37+
type Getter<T> = () => T;
38+
39+
/**
40+
* Стандартный код.
41+
* При сравнении двух сеттеров параметры в сигнатуре будут проверятся по контрвариантным правилам, а для геттеров возвращаемые типы по ковариантным.
42+
*/
43+
`````
44+
`````ts
45+
type Setter<in T> = (param: T) => void;
46+
type Getter<out T> = () => T;
47+
48+
/**
49+
* [Код с модификаторами]
50+
* Правила будут идентичны предыдущему примеру. Разница лишь в явной конкретизации.
51+
*/
52+
`````
53+
`````ts
54+
type Setter<out T> = (param: T) => void; // [0]
55+
type Getter<in T> = () => T; // [1]
56+
57+
/**
58+
* [Код с модификаторами]
59+
* К тому же, нельзя изменить поведение, то есть - нельзя поменять модификаторы местами!
60+
*/
61+
62+
/**
63+
* [0]
64+
* Type 'Setter<sub-T>' is not assignable to type 'Setter<super-T>' as implied by variance annotation.
65+
* Types of parameters 'param' and 'param' are incompatible.
66+
* Type 'super-T' is not assignable to type 'sub-T'.ts(2636)
67+
*/
68+
69+
/**
70+
* [1]
71+
* Type 'Getter<super-T>' is not assignable to type 'Getter<sub-T>' as implied by variance annotation.
72+
* Type 'super-T' is not assignable to type 'sub-T'.ts(2636)
73+
*/
74+
`````
75+
76+
Проще всего воспринимать эти модификаторы, как указание на то, что тип будет использоваться во входных параметрах (`<in T>`) или выходных (`<out T>`) или и то и другое одновременно `<in out T>`.
77+
78+
`````ts
79+
/**
80+
* Указание на то, что тип используется во входных и в выходных параметрах.
81+
*/
82+
type Func<in out T> = (param: T) => T;
83+
`````

0 commit comments

Comments
 (0)