Frontend
TypeScript #
Junior #
Что такое пользовательский тип данных
|
Пользовательский тип описывает доменную модель приложения с помощью
Хороший тип выражает ограничения предметной области и делает недопустимые состояния трудными для представления. Для вариантов состояния удобно использовать discriminated union, а для runtime-поведения и DI — классы. |
Что такое Union Type (тип объединения) и для чего используется?
|
Union type означает, что значение может принадлежать одному из нескольких типов:
Перед использованием специфичных свойств union нужно сузить тип через Discriminated union часто лучше набора независимых boolean-флагов: он не позволяет одновременно представить
несовместимые состояния, например |
Что такое декоратор и какие виды декораторов вы знаете?
|
Декоратор — способ добавления метаданных к объявлению класса. Это специальный вид объявления, который может быть присоединен к объявлению класса, методу, методу доступа, свойству или параметру. Декораторы используют форму @expression, где expression - функция, которая будет вызываться во время выполнения с информацией о декорированном объявлении. И, чтобы написать собственный декоратор, нам нужно сделать его factory и определить тип:
Декоратор класса Вызывается перед объявлением класса, применяется к конструктору класса и может использоваться для наблюдения, изменения или замены определения класса. Expression декоратора класса будет вызываться как функция во время выполнения, при этом конструктор декорированного класса является единственным аргументом. Если класс декоратора возвращает значение, он заменит объявление класса вернувшимся значением.
Декоратор свойства Объявляется непосредственно перед объявлением метода. Будет вызываться как функция во время выполнения со следующими двумя аргументами:
Декоратор метода Объявляется непосредственно перед объявлением метода. Будет вызываться как функция во время выполнения со следующими двумя аргументами:
Декоратор параметра Объявляется непосредственно перед объявлением метода. Будет вызываться как функция во время выполнения со следующими двумя аргументами:
|
Middle #
Зачем нам нужны определения типов, где есть JavaScript c динамической типизацией?
|
Динамическая типизация удобна во время выполнения, но многие ошибки можно обнаружить раньше:
TypeScript добавляет статический анализ, автодополнение, безопасный рефакторинг и явные контракты между частями приложения. Типы не заменяют runtime-валидацию: данные от API, пользователя и внешних систем все равно считаются недоверенными и должны проверяться. После компиляции большинство типов удаляется, а браузер выполняет обычный JavaScript. |
Поддерживает ли TypeScript перегрузку методов?
|
Да. TypeScript поддерживает несколько сигнатур перегрузки и одну общую реализацию.
Сигнатура реализации не видна вызывающему коду и должна быть совместима со всеми перегрузками. В runtime существует только одна JavaScript-функция, поэтому различение вариантов выполняет сама реализация. Если union-параметр дает такой же понятный API, обычно он проще перегрузок. |
Возможна ли перегрузка конструктора в TypeScript?
|
Да, с тем же ограничением: можно описать несколько сигнатур, но реализация конструктора остается одна.
Нельзя написать несколько тел |
Поддерживает ли TypeScript перегрузку методов (конструкторов)?
|
TypeScript поддерживает перегрузку функций, методов и конструкторов на уровне типов. Сначала объявляются доступные вызывающему коду сигнатуры, затем одна совместимая реализация. В скомпилированном JavaScript остается одна функция или один конструктор. Поэтому перегрузка не выбирает разные реализации автоматически: код должен сам сузить аргументы. Перегрузки нужны, когда разные наборы аргументов дают разные, точно связанные возвращаемые типы. Для простых случаев предпочтительнее union types, optional-параметры или объект параметров. |
Продвинутый TypeScript #
Middle #
Чем type отличается от interface и что такое intersection type?
|
Intersection |
Как типизировать состояние, API response и конфигурацию Angular-компонента?
|
Для состояний удобен discriminated union:
API DTO отделяют от доменной модели и преобразуют на data-access границе. Inputs типизируют максимально узко:
Конфигурации проверяют через |
Как типами описать дерево в TypeScript?
|
Для дерева обычно описывают узел с payload и дочерними узлами. Если структура readonly для потребителей, это стоит отразить в типе:
Такой тип подходит для меню, router-like конфигурации, дерева категорий или результата парсинга. Если у узлов бывают разные виды, лучше использовать discriminated union.
Discriminant |
Зачем использовать readonly-типы для структур данных?
|
Readonly-тип не делает данные глубоко immutable в runtime, но улучшает контракт и снижает риск случайной мутации. Обновление состояния лучше выражать созданием новой структуры:
|
Middle+ or Senior #
Что такое generics, generic constraints и keyof?
|
Generic позволяет сохранить связь между входными и выходными типами:
Generics нужны для reusable API, но не должны превращать простой код в сложную type-level программу. |
Что такое mapped, conditional types и infer?
|
Mapped type преобразует свойства существующего типа:
Conditional type выбирает тип по условию:
В прикладном коде сначала используют стандартные utility types: |
Чем satisfies отличается от as?
|
Для конфигураций, route maps и provider options предпочтителен |
Почему unknown безопаснее any и как писать type guards?
|
Type guard с предикатом |
Как типизировать граф или dependency graph?
|
Для adjacency list удобно использовать
Если нужно хранить дополнительные данные о ребре, вводят отдельный тип:
В frontend такие типы встречаются в визуализации зависимостей, build tooling, state machines и flows навигации. Типы фиксируют форму данных, но cycle detection и валидация внешнего JSON все равно остаются runtime-логикой. |
Когда generic data structure оправдана?
|
Generic-структура оправдана, когда один алгоритм действительно работает с разными типами значений и сохраняет связь между входом и выходом.
Если структура нужна только для одного доменного типа, отдельный generic может быть лишним. Например,
|
TypeScript и runtime-контракты #
Middle #
Чем generic constraints отличаются от intersection types?
|
Constraint говорит: “принимаю любой тип, но у него должен быть |
Как типизировать тестовые double без any?
|
Для stub обычно достаточно
Так тест не зависит от лишних методов и не теряет типовую проверку. Если mock framework возвращает широкие типы, лучше
изолировать unsafe interop в маленьком helper и не распространять |
Когда нужны declaration files .d.ts?
|
В библиотеке declaration files являются частью публичного API. Их нужно проверять вместе с build и не использовать для скрытия реальных несовпадений между TypeScript и runtime. |
Middle+ or Senior #
Почему generic type parameter не дает runtime safety?
|
Generic существует только на этапе компиляции и стирается в JavaScript. Если данные приходят из API,
Такой helper удобен, но он доверяет внешним данным. Для важных контрактов нужна runtime validation: schema, hand-written guard или adapter на границе API. Хороший ответ разделяет compile-time типы и проверку данных, которые пришли извне. Follow-up вопросы:
|