Питання на співбесіді з TypeScript з відповідями
Типи, дженерики, звуження, утилітарні та умовні типи, конфігурація і типізація React.
225 запитань для співбесіди з теми TypeScript з відповідями й поясненнями - рівні Junior, Middle і Senior. Приклади запитань, онлайн-тести й задачі на код.
- Generics
- Narrowing
- Utility types
- tsconfig
Запитання за рівнями
Junior
Базові поняття та синтаксис · 50 запитань
Middle
Практика, нюанси й оптимізація · 50 запитань
Senior
Архітектура, внутрішня будова, edge cases · 50 запитань
Приклади запитань
Кілька запитань із кожного рівня з правильною відповіддю й поясненням.
TypeScript · Junior
- Що таке TypeScript?
Правильна відповідь: Надмножина JavaScript зі статичною типізацією, що компілюється в JS
Будь-який валідний JS - майже завжди валідний TS. Типи перевіряються під час компіляції, а потім стираються: у рантаймі виконується звичайний JavaScript, і перевірок типів там немає. Тому дані ззовні (API, форми) однаково валідують у рантаймі - наприклад, через Zod.
- Чи є перевірка типів TypeScript під час виконання програми?
Правильна відповідь: Ні: типи стираються під час компіляції, у рантаймі працює звичайний JS
TypeScript - інструмент часу розробки. Якщо API поверне
nullзамість об'єкта, типи не врятують. Для рантайм-перевірок використовуютьtypeof/instanceofі бібліотеки схем (Zod, Valibot), з яких можна вивести й TS-типи. - Чим
unknownвідрізняється відany?Правильна відповідь: З
unknownнічого не можна робити без звуження типу, аanyвимикає перевіркиanyвимикає типізацію й «заражає» все, до чого торкається.unknown- безпечний аналог: значення може бути чим завгодно, але використовувати його можна лише після перевірки (typeof x === 'string'). Для даних ізJSON.parseіcatch (e)правильнішеunknown. - Що означає тип
never?Правильна відповідь: Тип значення, якого не може бути: функція ніколи не повертає керування
never- порожній тип. Його повертають функції, що завжди кидають виняток або зациклюються. Також він з'являється за повного звуження union-типу - на цьому побудована перевірка вичерпногоswitch.void- функція завершується, але результат не використовується.
TypeScript · Middle
- Що означає
<T extends { id: string }>у дженерику?Правильна відповідь: Обмеження:
Tмає мати принаймні властивістьid: stringConstraint дає змогу всередині функції безпечно звертатися до
item.id, зберігаючи повний типTу результаті. Передати можна будь-який об'єкт із відповіднимidта іншими полями. Класи й успадкування тут ні до чого. - Як типізувати функцію
getProp(obj, key), щоб результат залежав від ключа?Правильна відповідь:
function getProp<T, K extends keyof T>(obj: T, key: K): T[K]K extends keyof Tдозволяє лише наявні ключі, а індексний доступT[K]дає точний тип значення:getProp(user, 'age')→number. Варіант зanyвтрачає типізацію, аstringпропустить помилку в назві. - Що робить умовний тип
T extends string ? 'text' : 'other'?Правильна відповідь: Обирає один із типів залежно від того, чи сумісний
TзіstringУмовні типи - «тернарник» на рівні типів. Разом з
inferвони дають змогу видобувати частини типів. Застосовані до union, вони розподіляються по кожному члену (distributive conditional types). - Що робить
inferуtype ElementType<T> = T extends (infer U)[] ? U : never?Правильна відповідь: Оголошує змінну типу
U, яку TS виводить зі збігу з шаблономinferвикористовується лише вextends-частині умовного типу: TS зіставляєTіз шаблоном і «захоплює» потрібну частину.ElementType<string[]>→string. Так влаштованіReturnType,Parameters,Awaited.
TypeScript · Senior
- Чи можна за
strictFunctionTypesприсвоїти(x: Dog) => voidзмінній типу(x: Animal) => void?Правильна відповідь: Ні: параметри функцій перевіряються контраваріантно
Змінна обіцяє приймати будь-яке
Animal, а функція вміє працювати лише зDog- виклик ізCatзламається. Тому підтип за параметром іде у зворотний бік:(x: Animal) => voidможна присвоїти туди, де чекають(x: Dog) => void, але не навпаки. - Чому
strictFunctionTypesне діє на метод, оголошений якhandle(x: Dog): void?Правильна відповідь: Параметри методів (method syntax) перевіряються біваріантно заради сумісності
Біваріантність методів залишили, щоб багато вбудованих типів (наприклад,
Array<T>) лишалися сумісними. Якщо оголосити властивість-функціюhandle: (x: Dog) => void, перевірка буде строгою. Тому для колбеків в інтерфейсах часто обирають синтаксис властивості. - Чому дорівнює
ToArray<string | number>, якщоtype ToArray<T> = T extends any ? T[] : never?Правильна відповідь:
string[] | number[]Умовний тип над «голим» параметром розподіляється по union: умова застосовується до кожного члена окремо. Це distributive conditional type - на ньому побудовані
ExcludeіExtract. - Як вимкнути розподіл умовного типу по union?
Правильна відповідь: Обгорнути обидві сторони в кортеж:
[T] extends [U] ? X : YРозподіл спрацьовує лише тоді, коли тип, що перевіряється, - «голий» параметр. Кортеж
[T]робить його складеним, і union перевіряється цілком:[string | number] extends [string]→ false. Налаштування компілятора для цього немає.
Збірні тести з цією темою
Запитання з кількох тем одразу - як на співбесіді на конкретну вакансію.
Задачі на код
Напишіть рішення просто в браузері - тести перевірять його одразу. Класика співбесід: debounce, throttle, deepClone, Promise.all, EventEmitter, LRU-кеш та інші.
Відкрити задачі →