У меня есть очень простой пример, где TypeScript (3.5.1) нормально работает с кодом, но при запуске сразу выдает ошибку.
Я считаю, что проблема здесь в том, что по сути value
это объявлен, но не инициализирован до запуска getValue
. Это довольно неинтуитивно, но я понимаю, как работает JS.
Однако почему TS не может обнаружить эту проблему в таком простом примере? Поскольку value
является константой, мне кажется, что TS должен точно определить, когда он установлен, и предсказать, что этот код сработает.
console.info(getValue());
const value = "some string";
function getValue() {
return value;
}
Во втором примере без вызова функции TS улавливает, что переменная используется до присваивания:
console.info(value);
const value = "some string";
Заявление TSLint о неиспользовании до объявления также неприменимо.
Предполагая, что TS/linting не сможет это отловить, есть ли наилучшая практика, которую можно применить в начальном примере, чтобы избежать этого сбоя? Например, «всегда объявлять константы на уровне модуля в верхней части файла».
Происходит это из-за подъема в JS (функция поднимается, const — нет). Кажется, что ts не проверяет такие вещи, как подъем. Вы можете посмотреть github.com/Microsoft/TypeScript/issues/19819 Эта проблема также с подъемом, но ничего не было предложено
Я думаю, что статическому анализу трудно точно обнаружить ошибки временная мертвая зона. Похоже, TypeScript обычно предпочитает ложноотрицательные результаты ложноположительным для такого рода вещей.
См. также Microsoft/TypeScript#13638
интересно. Даже правило no-use-before-declare
в tslint этого не уловило.
Вы можете включить only-arrow-functions
tslint, а затем заменить свой function getValue()
на
const getValue = function(): string {
return value;
}
или даже
const getValue = (): string => value;
В этот момент ваша первая строка будет ошибкой компилятора:
Block-scoped variable 'getValue' used before its declaration
«Всегда использовать лямбда» выглядит разумным решением. Раньше мы всегда использовали ключевое слово function
на верхнем уровне (глобальная область/область модуля) в первую очередь для улучшения стеков вызовов. (См. stackoverflow.com/a/23045200/152711). Но сейчас при тестировании узел (в данном случае ts-узел) фактически дает нам стеки вызовов, которые включают именованные лямбда-выражения, такие как const someLambda = () => null;
. Поэтому я не думаю, что есть веская причина использовать ключевое слово function
для наших целей. Мне также нравится, что использование const
, а не function
обеспечивает постоянную организацию наших файлов.
Я думаю, что приведенный выше ответ функции стрелки лучше всего отвечает на ваш вопрос, но в качестве примечания: принятие строгого рабочего процесса также предотвратит ошибки подъема: объявите vars, объявите функции, вызовите функцию инициализации:
const value = "some string"
function startApp() {
console.info(getValue());
}
function getValue() {
console.info("yo " + value)
return value;
}
startApp()
Мой ответ будет "тест". Система типов и язык могут фиксировать только некоторые категории ошибок. Точно так же нельзя ожидать, что программа не рухнет, если она компилируется на статически типизированном языке, таком как Java/C#.