Что такое TypeScript и зачем он нужен?
Вопрос
Что такое TypeScript, чем он отличается от JavaScript и зачем его использовать?
Короткий ответ
TypeScript — это надмножество JavaScript, добавляющее статическую типизацию. Он не выполняется браузером напрямую: компилятор (tsc) проверяет типы и транспилирует код в обычный JavaScript, после чего типы полностью исчезают — в рантайме их не существует.
Подробный ответ
Любой валидный JavaScript-код является валидным TypeScript-кодом — TS добавляется поверх, а не заменяет язык. Ключевые причины использовать TypeScript:
- Проверка типов на этапе компиляции. Ошибки вроде обращения к несуществующему свойству или передачи
stringвместоnumberнаходятся до запуска кода, а не в рантайме. - Автодополнение и рефакторинг в IDE. Типы дают редактору информацию для подсказок, перехода к определению и безопасного переименования.
- Документация в коде. Сигнатуры функций и интерфейсы описывают контракт без отдельных комментариев.
- Типы стираются при компиляции (erasure). В отличие от языков с рантайм-проверкой типов (Java, C#), TypeScript не добавляет никакой проверки типов во время выполнения — весь контроль происходит только на этапе
tsc.
TypeScript использует структурную типизацию (structural typing / duck typing), а не номинативную. Совместимость типов определяется формой (набором полей и их типов), а не именем класса или явным объявлением наследования — как в Java или C#, где нужно явно писать implements.
interface Point { x: number; y: number }
function printPoint(p: Point) {
console.log(`${p.x}, ${p.y}`)
}
// объект нигде не объявлен как Point, но подходит по форме
const vector = { x: 10, y: 20, z: 30 }
printPoint(vector) // OK — лишние поля не мешают, важна лишь совместимость структуры
В номинативной системе типов (Java) этот же вызов потребовал бы явной реализации интерфейса Point. В TypeScript достаточно, чтобы объект структурно удовлетворял требуемой форме.
Пример
// basics.ts
let age: number = 30
let name: string = 'Alice'
let isAdmin: boolean = false
// ошибка обнаруживается на этапе компиляции, а не в рантайме
// age = 'thirty' // Type 'string' is not assignable to type 'number'
function greet(user: { name: string; age: number }): string {
return `Привет, ${user.name}, тебе ${user.age}`
}
// после компиляции в JS все аннотации типов исчезают:
// function greet(user) { return `Привет, ${user.name}, тебе ${user.age}`; }
console.log(greet({ name, age }))
Дополнительные вопросы
- Чем структурная типизация отличается от номинативной и где TypeScript всё же ведёт себя "почти номинативно" (например, с приватными полями классов)?
- Что такое
tsconfig.jsonи за что отвечает флагstrict? - Почему TypeScript называют "надмножеством" (superset), а не отдельным языком?