Почему TypeScript не улавливает, что перед присваиванием используется константа?

У меня есть очень простой пример, где 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 не сможет это отловить, есть ли наилучшая практика, которую можно применить в начальном примере, чтобы избежать этого сбоя? Например, «всегда объявлять константы на уровне модуля в верхней части файла».

Мой ответ будет "тест". Система типов и язык могут фиксировать только некоторые категории ошибок. Точно так же нельзя ожидать, что программа не рухнет, если она компилируется на статически типизированном языке, таком как Java/C#.

unional 29.05.2019 23:55

Происходит это из-за подъема в JS (функция поднимается, const — нет). Кажется, что ts не проверяет такие вещи, как подъем. Вы можете посмотреть github.com/Microsoft/TypeScript/issues/19819 Эта проблема также с подъемом, но ничего не было предложено

Fyodor 30.05.2019 01:06

Я думаю, что статическому анализу трудно точно обнаружить ошибки временная мертвая зона. Похоже, TypeScript обычно предпочитает ложноотрицательные результаты ложноположительным для такого рода вещей.

jcalz 30.05.2019 02:29

См. также Microsoft/TypeScript#13638

jcalz 30.05.2019 02:33

интересно. Даже правило no-use-before-declare в tslint этого не уловило.

user6269864 30.05.2019 05:09
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
10
5
743
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете включить 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 обеспечивает постоянную организацию наших файлов.

Freewalker 30.05.2019 18:12

Я думаю, что приведенный выше ответ функции стрелки лучше всего отвечает на ваш вопрос, но в качестве примечания: принятие строгого рабочего процесса также предотвратит ошибки подъема: объявите vars, объявите функции, вызовите функцию инициализации:

const value = "some string"

function startApp() { 
    console.info(getValue());
}

function getValue() {
    console.info("yo " + value)
    return value;
}

startApp()

Другие вопросы по теме