Машинопись Type Guards и функция жирной стрелки

Разве это не должно правильно компилироваться? Я получаю ошибку "Property 'hello' does not exist on type 'object'. "в выделенной строке.

Я могу без проблем получить доступ к g.hello вне функции жирной стрелки.

class Test {
    constructor() {
    }
    hello() : string {
        return "Hello";
    }
}

let g : object;

if (g instanceof Test) {
    () => {
        g.hello();    ////// ERROR HERE /////
    };
}

person Roddy    schedule 05.12.2018    source источник


Ответы (2)


Сужение, которое тип-охранник делает для переменной (или чего-либо еще), не будет пересекать границы функций. Это ограничение конструкции.

Способ обойти эту проблему - присвоить g новой переменной, тип которой будет определяться на основе сужения. Доступ к новой переменной в функции стрелки будет работать должным образом:

class Test {
    constructor() {
    }
    hello() : string {
        return "Hello";
    }
}

let g : object;

if (g instanceof Test) {
    const gTest = g;
    () => {
        gTest.hello();
    };
}

Другой способ обойти эту проблему, если g не изменяется, - объявить g с помощью const. Это позволит компилятору сохранить сужение:

let g : object;

if (g instanceof Test) {
    const gTest = g;
    () => {
        gTest.hello();
    };
}

площадка Link

person Titian Cernicova-Dragomir    schedule 05.12.2018
comment
Ах, что = это +1 - person Chris W.; 06.12.2018
comment
@ChrisW. старое решение с новыми вариантами использования;) - person Titian Cernicova-Dragomir; 06.12.2018
comment
Думаю, этот ответ либо частично неверен, либо устарел. В TypeScript 3+ охранники типов могут пересекать границы функций для const-объявленных переменных. Изменение строки 9 в исходном вопросе на const g: object = new Test(); позволяет компилировать без ошибок. (Имеет смысл, что let сужение не будет пересекать границы функции, потому что переменная может быть снова присвоена object перед вызовом функции.) - person Miles; 08.04.2021
comment
@Miles Нет, проблема все еще существует, в частности, он должен делать с функцией стрелки () => typescriptlang .org / play? # code / - person Titian Cernicova-Dragomir; 08.04.2021
comment
Вы используете let, я сказал const: typescriptlang.org/play?#code/ Для меня это похоже на сужение границ пересекающихся функций. - person Miles; 08.04.2021
comment
@Miles Вы правы, похоже, это изменилось, или я пропустил это в то время. Я также добавлю это решение - person Titian Cernicova-Dragomir; 09.04.2021

let + стрелочная функция

class Test {
    constructor() {
    }
    hello() : string {
        return "Hello";
    }
}

declare let g : object;

if (g instanceof Test) {
    () => {
        g.hello(); // error
    };
}

g - это Test, когда функция определена, но g может не быть Test, когда функция выполняется.

const + стрелочная функция

class Test {
    constructor() {
    }
    hello() : string {
        return "Hello";
    }
}

declare const g : object;

if (g instanceof Test) {
    () => {
        g.hello(); // ok
    };
}

g неизменяемый, g всегда Test после определения функции.

const + обычная функция

class Test {
    constructor() {
    }
    hello() : string {
        return "Hello";
    }
}

declare const g : object;

if (g instanceof Test) {
    function f() {
        g.hello(); // error
    };
}

В базовой реализации обычная функция f определяется в ES5 var вместо ES6 let. подъем переменной поднимает объявление f, когда g может не быть Test .

person Zim    schedule 12.07.2021