Во что компилируется type guard в TypeScript
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Компиляция Type Guard в TypeScript
Type Guard — это функция, которая проверяет тип значения и помогает TypeScript сузить тип. Вот как они компилируются в JavaScript.
Важное уточнение
Type guard — это исключительно TypeScript конструкция. В JavaScript её вообще нет. Компилятор TypeScript полностью удаляет типы при компиляции.
Пример 1: Простой type guard
TypeScript код
// Функция type guard
function isString(value: unknown): value is string {
return typeof value === 'string';
}
function processValue(value: unknown) {
if (isString(value)) {
// Здесь value имеет тип string
console.log(value.toUpperCase());
} else {
// Здесь value имеет тип unknown
console.log(value);
}
}
JavaScript (скомпилированный)
// Компилятор удаляет тип guard синтаксис!
function isString(value) {
return typeof value === 'string';
}
function processValue(value) {
if (isString(value)) {
// Это всё ещё JavaScript
console.log(value.toUpperCase());
} else {
console.log(value);
}
}
Вывод: Type guard синтаксис value is string полностью удаляется. Остаётся только обычная функция с проверкой типа.
Пример 2: Type guard с объектом
TypeScript
interface User {
id: number;
name: string;
email: string;
}
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value &&
'email' in value &&
typeof (value as any).id === 'number' &&
typeof (value as any).name === 'string' &&
typeof (value as any).email === 'string'
);
}
function handleData(data: unknown) {
if (isUser(data)) {
// data имеет тип User
console.log(`User: ${data.name}`);
} else {
console.log('Not a user');
}
}
JavaScript
// Интерфейс удаляется полностью
// Type guard синтаксис удаляется
// Остаётся только логика проверки
function isUser(value) {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value &&
'email' in value &&
typeof value.id === 'number' &&
typeof value.name === 'string' &&
typeof value.email === 'string'
);
}
function handleData(data) {
if (isUser(data)) {
console.log(`User: ${data.name}`);
} else {
console.log('Not a user');
}
}
Пример 3: instanceof guard
TypeScript
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
bark() {
console.log('Woof!');
}
}
function processAnimal(animal: Animal) {
if (animal instanceof Dog) {
// animal имеет тип Dog
animal.bark();
}
}
JavaScript
// instanceof — это стандартный JavaScript оператор
// TypeScript типы удаляются
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
bark() {
console.log('Woof!');
}
}
function processAnimal(animal) {
if (animal instanceof Dog) {
animal.bark();
}
}
Какой синтаксис компилируется, а какой нет
Удаляется (только TypeScript)
// Type guard синтаксис удаляется
function isString(value: unknown): value is string { ... }
// ^^^^^^^^^^^^^^^
// Это удалится
// Типы параметров удаляются
function add(a: number, b: number) { ... }
// ^^^^^^^^ ^^^^^^^^
// Удалится
// Типы переменных удаляются
const user: User = { ... };
// ^^^^^
// Удалится
// Интерфейсы и type удаляются полностью
interface User { ... }
type Status = 'pending' | 'done';
Остаётся (JavaScript)
// Логика проверки остаётся
if (typeof value === 'string') { ... }
// Это стандартный JavaScript
// instanceof остаётся
if (value instanceof Array) { ... }
// Это стандартный JavaScript
// Условная логика остаётся
if (value !== null && 'name' in value) { ... }
// Это стандартный JavaScript
Эффект type guard на производительность
Нет никакого эффекта
Type guard не добавляет никакого overhead, потому что он удаляется при компиляции:
// TypeScript
function isString(value: unknown): value is string {
return typeof value === 'string';
}
// JavaScript (идентично)
function isString(value) {
return typeof value === 'string';
}
// Оба варианта имеют идентичную производительность
Пример 4: Discriminated union type guard
TypeScript
type Result =
| { status: 'success'; data: string }
| { status: 'error'; error: Error };
function isSuccess(
result: Result
): result is { status: 'success'; data: string } {
return result.status === 'success';
}
function handleResult(result: Result) {
if (isSuccess(result)) {
// result имеет тип { status: 'success'; data: string }
console.log(result.data);
} else {
// result имеет тип { status: 'error'; error: Error }
console.log(result.error);
}
}
JavaScript
// Типы удалены, остаётся только логика
function isSuccess(result) {
return result.status === 'success';
}
function handleResult(result) {
if (isSuccess(result)) {
console.log(result.data);
} else {
console.log(result.error);
}
}
Пример 5: Custom type guard
TypeScript
type NonEmptyString = string & { readonly __brand: 'NonEmptyString' };
function isNonEmptyString(value: string): value is NonEmptyString {
return value.length > 0;
}
function greet(name: NonEmptyString) {
console.log(`Hello, ${name}`);
}
const userName = 'Alice';
if (isNonEmptyString(userName)) {
greet(userName);
}
JavaScript
// Brand типы удалены, остаётся логика
function isNonEmptyString(value) {
return value.length > 0;
}
function greet(name) {
console.log(`Hello, ${name}`);
}
const userName = 'Alice';
if (isNonEmptyString(userName)) {
greet(userName);
}
Как TypeScript узнаёт, что это type guard?
TypeScript смотрит на возвращаемый тип функции:
// Обычная функция — возвращает boolean
function isString(value: unknown): boolean {
return typeof value === 'string';
}
const str: unknown = 'hello';
if (isString(str)) {
// TypeScript думает, что str всё ещё unknown
str.toUpperCase(); // ошибка!
}
// Type guard функция — возвращает 'value is Type'
function isStringGuard(value: unknown): value is string {
return typeof value === 'string';
}
const str: unknown = 'hello';
if (isStringGuard(str)) {
// TypeScript знает, что str имеет тип string
str.toUpperCase(); // OK!
}
Когда type guard становится проверкой в runtime
Type guard определяет логику, которая выполняется в runtime:
// TypeScript (compile-time)
function isString(value: unknown): value is string {
// ^^^^^^^^^^^^^^^ - это только для TypeScript
return typeof value === 'string'; // это выполнится в runtime
}
// Runtime:
// 1. Вызывается функция isString
// 2. Выполняется typeof value === 'string'
// 3. Возвращается boolean
// 4. TypeScript уже скомпилировался, он не участвует
Best Practices
1. Используй type guard вместо множественных проверок
// ПЛОХО: проверка дублируется
if (typeof value === 'string' && value.length > 0) {
const str = value as string; // нужно приводить тип
console.log(str.toUpperCase());
}
// ХОРОШО: type guard
function isNonEmptyString(v: unknown): v is string {
return typeof v === 'string' && v.length > 0;
}
if (isNonEmptyString(value)) {
console.log(value.toUpperCase()); // TypeScript знает тип
}
2. Типы в type guard должны быть точными
// Правильный синтаксис
function isUser(value: unknown): value is User { ... }
// Неправильный синтаксис
function isUser(value: unknown): value is User | Admin { ... }
// Лучше вернуть union type
function isUserOrAdmin(value: unknown): value is (User | Admin) { ... }
3. Type guard логика должна соответствовать типу
// ХОРОШО: логика соответствует типу
function isUser(obj: unknown): obj is { name: string; email: string } {
return (
typeof obj === 'object' &&
obj !== null &&
'name' in obj &&
'email' in obj &&
typeof obj.name === 'string' &&
typeof obj.email === 'string'
);
}
// ПЛОХО: логика не проверяет всё
function isUser(obj: unknown): obj is { name: string; email: string } {
return typeof obj === 'object'; // слишком слабо!
}
Интересный факт
Type guard — это нулевой стоимости абстракция. То есть:
TypeScript с type guard: ✓ Type-safe
JavaScript эквивалент: ✓ Идентичная производительность
Вы платите только за логику проверки типа в runtime,
Без каких-либо额额ных затрат на сам type guard.
Итог
Type guard компилируется в:
- Удаление синтаксиса
value is Type— это TypeScript only - Сохранение логики проверки — это остаётся в JavaScript
- Обычная функция — которая возвращает boolean
Type guard — это инструмент TypeScript для сужения типов. В runtime это просто функция, которая проверяет условие. Никакого магии или overhead.