#typescript #typescript-compiler-api
#машинописный текст #typescript-compiler-api
Вопрос:
После инициализации API компилятора typescript следующим образом…
const program = ts.createProgram(fileNames, options);
const checker = program.getTypeChecker();
теперь программа скомпилирована, что означает, что программа typescript прошла всю программу один раз и получила возможность создать таблицу типов.
В отладочной версии typescript, доступной на github, есть функция проверки …
ts.getTypeChecker().getTypeCatalog()
но в версии выпуска она недоступна.
Цитирую из ограниченной документации, которая описывает только на концептуальном уровне, без примеров:
Символ: именованное объявление. Символы создаются в результате привязки. Символы соединяют узлы объявления в дереве с другими объявлениями, вносящими вклад в один и тот же объект. Символы являются основным строительным блоком семантической системы. Тип: Типы являются другой частью семантической системы. Типы могут быть именованными (например, классы и интерфейсы) или анонимными (например, типы объектов).
Первое, что сделает средство проверки типов, — это объединить все символы из разных исходных файлов в единое представление и создать единую таблицу символов путем «слияния» любых общих символов (например, пространств имен, охватывающих несколько файлов).
После инициализации исходного состояния средство проверки типов готово ответить на любые вопросы о программе. Такие «вопросы» могут быть:
Какой символ для этого узла? Каков тип этого символа? Какие символы видны в этой части AST? Каковы доступные подписи для объявления функции? О каких ошибках следует сообщать для файла?
Средство проверки типов вычисляет все лениво; он только «разрешает» необходимую информацию для ответа на вопрос. Проверка будет проверять только узлы / символы / типы, которые вносят вклад в рассматриваемый вопрос, и не будет пытаться исследовать дополнительные объекты.
Итак, чтобы ответить на мой собственный вопрос: да и нет.
Да, потому что «TypeChecker … объединит все символы из разных исходных файлов в одно представление».
Нет, потому что «Средство проверки типов вычисляет все лениво; он только «разрешает» необходимую информацию для ответа на вопрос».
Доступно несколько десятков функций ts.getTypeChecker()
— они недокументированы, и в примерах нет примеров использования для случая разрешения «глубоких» типов.
Я успешно использовал ts.getTypeChecker.forEachChild(...)
для обхода файла и, например, поиска объявлений функций. Но с типом в руке я не знаю, как использовать средство проверки для изменения типа и создания иерархии вплоть до примитивов.
Комментарии:
1. Это где-нибудь в документах?
2. @Daniel_Knights — я расширил вопрос в ответ на ваш комментарий.
3. Я все еще не могу найти ни одной ссылки на
getTypeCatalog
.4. Здесь говорится: «Имейте в виду, что это еще не стабильный API …».
Ответ №1:
Лучшее место для поиска этой информации — исходный код компилятора TypeScript.
getTypeCatalog
Функция является внутренней и не является частью общедоступного API (исходного кода):
interface TypeChecker {
// ...omitted...
/* @internal */ getTypeCatalog(): readonly Type[];
// ...omitted...
}
Я не уверен, что доступ к ней настолько полезен.
Я успешно использовал ts.getTypeChecker.forEach(…) для обхода файла и, например, поиска объявлений функций. Но с типом в руке я не знаю, как использовать средство проверки для изменения типа и создания иерархии вплоть до примитивов.
Я не думаю forEach
, что функция существует на TypeChecker
(возможно, вы имели в виду forEach
на символе?).
Для этого вы можете получить исходный файл ASTs ( program.getSourceFiles()
), просмотреть их с помощью sourceFile.forEachChild(child => { /* call child.forEachChild recursively */ })
, затем вы можете использовать typeChecker.getTypeAtLocation(child)
для получения типов.
Комментарии:
1. Я изменился
forEach
наforEachChild
. Очевидно, я бы не повторил дерево без использованияforEachChild
.getTypeAtLocation
возвращает тип идентификатора, который не отвечает на мой вопрос. «Прочитать код» — да, но в любом случае это значение по умолчанию.2. @CraigHicks
forEachChild
доступен для любогоNode
или экспортируемогоts
модуля (не для TypeChecker). Извините, некоторые люди могут просматривать символы, а не AST, так что это не так очевидно … особенно при обсужденииforEach
, который является символьным методом. Другими словами, я не верю, что это возможно получить через общедоступный API. Вероятно, вам лучше всего использовать объявления и использоватьgetTypeAtLocation
(или, возможно, использоватьgetSymbolAtLocation
иgetSymbolsInScope
в зависимости от вашей ситуации). ИспользованиеType#getBaseTypes
иType#getProperties()
может быть полезным.3. getSymbolsInScope дает полезные результаты.