У Typescript, що таке! (знак оклику / вибуху) оператора при відправленні члена?


453

Переглядаючи вихідний код для правила tslint, я натрапив на таке твердження:

if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}

Помітьте !оператора після node.parent. Цікаво!

Я спершу спробував скомпілювати файл локально з моєю інстальованою версією TS (1.5.3). Отримана помилка вказувала на точне розташування чубчика:

$ tsc --noImplicitAny memberAccessRule.ts 
noPublicModifierRule.ts(57,24): error TS1005: ')' expected.

Далі я перейшов до останнього TS (2.1.6), який склав його без проблем. Тож, здається, це властивість TS 2.x. Але транспіляція повністю ігнорувала удар, в результаті чого з'явився наступний JS:

if (node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}

Мій Google фу поки що не зміг мене.

Що таке оператор знака оклику та як він працює?

Відповіді:


691

Це ненульовий оператор твердження. Це спосіб сказати компілятору "цей вираз не може бути nullабо undefinedтут, тому не нарікайте на можливість його існування nullабо undefined". Іноді перевіряючий тип не може самостійно визначити це визначення.

Це пояснюється тут :

Новий !оператор виразів після виправлення може бути використаний для того, щоб стверджувати, що його операнд є ненульовим і невизначеним у контекстах, коли перевіряючий тип не може зробити висновок про цей факт. Зокрема, операція x!видає значення типу xз nullі undefinedвиключено. Подібно до типових тверджень форм <T>xі x as T, !ненульовий оператор твердження просто видаляється з випущеного коду JavaScript.

Я вважаю використання терміна "стверджувати" трохи оманливим у цьому поясненні. Це "стверджувати" в тому сенсі, що розробник це стверджує , а не в тому сенсі, що буде проведено тестування. Останній рядок дійсно вказує на те, що в результаті не видається код JavaScript.


102
Гарний заклик до «твердження» двозначності.
колба Естуса

8
Гарне пояснення. Я вважаю гарною практикою робити console.assert()відповідну змінну, перш ніж додавати !після неї. Оскільки !команда add вказує компілятору ігнорувати нульову перевірку, вона компілюється в noop в JavaScript. Тож якщо ви не впевнені, що змінна не є нульовою, тоді краще зробіть явну перевірку затвердження.
Jayesh

12
Як мотивуючий приклад: використання нового типу ES Map з таким кодом, як dict.has(key) ? dict.get(key) : 'default';компілятор TS, не може зробити висновок про те, що getвиклик ніколи не повертається null / undefined. dict.has(key) ? dict.get(key)! : 'default';правильно звужує тип.
kitsu.eb

1
Чи є сленг для цього оператора, як, наприклад, оператор Елвіса ставиться до двійкового оператора?
ebakunin

@Jayesh Ви могли б розширити консоль.assert () належної практики, чи можете ви розмістити приклад?
Крістофер Франсіско

168

Відповідь Луї чудова, але я думав, що спробую її коротко підсумувати:

Оператор вибуху повідомляє компілятору тимчасово послабити обмеження "не нульового", яке може інакше вимагати. Він каже компілятору: "Як розробник, я краще за вас знаю, що ця змінна зараз не може бути нульовою".


85
Потім, як розробник, ви заплуталися.
Майк Чемберлен

9
Або, як компілятор, він заплутався. Якщо конструктор не ініціалізує властивість, але гак життєвого циклу робить це, і компілятор цього не розпізнає.
Мукус

26
Це не відповідальність компілятора ТС. На відміну від деяких інших мов (наприклад, C #), JS (і, отже, TS) не вимагає, щоб змінні ініціалізувалися перед використанням. Або, щоб подивитися на це по-іншому, в JS всі змінні, оголошені з varабо letнеявно ініціалізовані undefined. Крім того, властивості екземплярів класу можна оголосити як такі, тому class C { constructor() { this.myVar = undefined; } }цілком законно. Нарешті, гачки життєвого циклу залежать від рамки; наприклад, Angular та React реалізують їх по-різному. Тож не можна очікувати, що компілятор TS пояснить їх.
Майк Чемберлен

1
Чи є дійсний випадок використання оператора нахилу, враховуючи дивовижність аналізу типу на основі потоку управління в ТС?
Євген Каратаєв

1
@EugeneKarataev Так, рамки часто ініціалізують змінні всередині себе, і аналіз потоку управління ts не може його наздогнати. Його використання, безумовно, зменшено, але ви натрапите на випадки, коли це потрібно.
arg20
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.