Що робить ключове слово `is` у машинописі?


109

Я натрапив на код, який виглядає так:

export function foo(arg: string): arg is MyType {
    return ...
}

Я не міг шукати isні в документах, ні в google, це досить поширене слово і відображається практично на кожній сторінці.

Що робить ключове слово у цьому контексті?

Відповіді:


115
function isString(test: any): test is string{
    return typeof test === "string";
}

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length); // string function
    }
}
example("hello world");

Використовуючи предикат типу "test is string" у наведеному вище форматі (замість того, щоб просто використовувати boolean для типу return, після виклику isString (), якщо функція повертає true, TypeScript звузить тип до рядка в будь-якому блоці, що охороняється виклик функції. Компілятор подумає, що foo є рядком у блоці, що охороняється нижче (і ТІЛЬКИ в блоці, що охороняється нижче)

{
    console.log("it is a string" + foo);
    console.log(foo.length); // string function
}

Присудок типу просто використовується під час компіляції. Результат .js-файл (час виконання) не матиме різниці, оскільки він не враховує ТИП.

Я проілюструю відмінності нижче на чотирьох прикладах.

Напр. 1: у наведеному вище прикладі коду не буде помилок компіляції та помилок виконання.

Напр. 2: наведений нижче приклад коду матиме помилку компіляції (а також помилку виконання), оскільки TypeScript звузив тип до рядка та перевірив, що toExponential не належить до рядкового методу.

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
        console.log(foo.toExponential(2));
    }
}

Напр. 3: наведений нижче приклад коду не має помилки компіляції, але матиме помилку виконання, оскільки TypeScript ТІЛЬКИ звузить тип до рядка в блоці, що охороняється, але не після, тому foo.toExponential не створить помилку компіляції (TypeScript не вважає, що це так тип рядка). Однак під час виконання рядок не має методу toExponential, тому він матиме помилку виконання.

function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
    }
    console.log(foo.toExponential(2));
}

Напр. 4: якщо ми не використовуємо "test is string" (предикат типу), TypeScript не буде звужувати тип у блоці, що охороняється, і наведений нижче приклад коду не матиме помилки компіляції, але матиме помилку виконання.

function isString(test: any): boolean{
    return typeof test === "string";
}
function example(foo: any){
    if(isString(foo)){
        console.log("it is a string" + foo);
        console.log(foo.length);
        console.log(foo.toExponential(2));
    }
}

Висновок полягає в тому, що "тест - це рядок" (предикат типу) використовується під час компіляції, щоб повідомити розробникам, що у коду буде можливість помилки виконання. Щодо javascript, розробники не знатимуть про помилку під час компіляції. Це перевага використання TypeScript.


11

Єдине використання, яке я знаю, - це ваш приклад: вказати "предикат типу" ( arg is MyType) у визначеному користувачем Type Guard

Див. Користувальницькі охорони типу у цьому посиланні

Ось ще одне посилання


1
Я теж це бачив у документах, яке химерне дизайнерське рішення, цю справу можна повністю вирішити, повернувши тип booleanправильно?
— Бенджамінц

2
@benjaminz Це може виправдати власне запитання щодо SO, але я можу показати вам короткий приклад того, як вони відрізняються. isКлючове слово фактично заливка помилки типу і можна ввести зловити пізніше в коді. Дивіться цей приклад для отримання додаткової інформації.
— стайфл

@benjaminz Я не розумію, як з цим можна впоратись булевим значенням. Машинопис повинен знати, що функція, в яку ви передаєте об’єкт, функціонує як захист типу. Якщо він просто повертає тип true або false, звідки Typescript може знати, що це справді захист типу, а не просто якась довільна функція, яка повертає true, якщо об'єкт неправдивий. Як він дізнається, як звузити тип об’єкта? По-друге, як він може знати, до якого типу звузити тип об’єкта? Що робити, якщо параметр є одним із трьох типів? Потрібно знати, що trueвідповідає певному типу.
— pushkin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.