В TypeScript **function overloads** позволяют объявить несколько сигнатур для одной функции. Это нужно когда функция ведёт себя по-разному в зависимости от типов аргументов.
// Перегрузка: разные сигнатуры вызова
function createDate(timestamp: number): Date
function createDate(month: number, day: number, year: number): Date
// Реализация (не видна снаружи):
function createDate(monthOrTimestamp: number, day?: number, year?: number): Date {
if (day !== undefined && year !== undefined) {
return new Date(year, monthOrTimestamp - 1, day)
} else {
return new Date(monthOrTimestamp)
}
}
// Вызовы:
createDate(1609459200000) // OK — по timestamp
createDate(1, 15, 2024) // OK — месяц, день, год
createDate(15, 2024) // Ошибка TS: нет подходящей перегрузки// 1. Сигнатуры перегрузок (overload signatures) — только для TypeScript, не выполняются:
function reverse(str: string): string
function reverse(arr: number[]): number[]
// 2. Сигнатура реализации — должна быть совместима со всеми перегрузками:
function reverse(input: string | number[]): string | number[] {
if (typeof input === 'string') {
return input.split('').reverse().join('')
}
return [...input].reverse()
}
// TypeScript знает точные типы при вызове:
const str = reverse('hello') // тип: string
const arr = reverse([1, 2, 3]) // тип: number[]1. Должно быть **минимум 2 сигнатуры перегрузки**
2. Сигнатура реализации **не участвует** в разрешении перегрузки — она только реализует логику
3. Сигнатура реализации должна быть **совместима** со всеми перегрузками
4. Более **специфичные** сигнатуры должны идти **раньше** общих
// Плохо — менее специфичная сигнатура первой может затенить другие:
function format(value: string | number): string // слишком общая
function format(value: number, digits: number): string // никогда не выбирается!
// Хорошо — специфичные первыми:
function format(value: number, digits: number): string
function format(value: string | number): stringКлассический пример из DOM API:
// В TypeScript встроено (упрощённо):
function querySelector(selector: string): Element | null
function querySelector<T extends Element>(selector: string): T | null
// Реальный usecase:
const input = document.querySelector<HTMLInputElement>('#name')
// input: HTMLInputElement | nullИспользуй перегрузки когда:
Не используй когда:
string | numberfunction foo(a: string, b?: number)function identity<T>(x: T): T// Не нужна перегрузка — достаточно optional параметра:
function greet(name: string, greeting?: string): string {
return `${greeting ?? 'Привет'}, ${name}!`
}
// Нужна перегрузка — разные входные/выходные типы:
function parse(input: string): string[]
function parse(input: string[]): string
function parse(input: string | string[]): string | string[] {
if (typeof input === 'string') return input.split(',')
return input.join(',')
}Паттерны перегрузки функций в JavaScript: dispatch по типу аргументов
// В TS: function overloads — разные сигнатуры для одной функции
// В JS: реализуем через проверку типов аргументов
// === Паттерн 1: reverse для строк и массивов ===
function reverse(input) {
// В TS:
// function reverse(str: string): string
// function reverse(arr: number[]): number[]
if (typeof input === 'string') {
return input.split('').reverse().join('')
}
if (Array.isArray(input)) {
return [...input].reverse()
}
throw new TypeError(`Ожидается строка или массив, получено: ${typeof input}`)
}
console.log('=== reverse ===')
console.log(reverse('hello')) // 'olleh'
console.log(reverse('TypeScript')) // 'tpircSepyT'
console.log(reverse([1, 2, 3, 4])) // [4, 3, 2, 1]
console.log(reverse(['a', 'b', 'c'])) // ['c', 'b', 'a']
// === Паттерн 2: createDate — по timestamp или по дате ===
function createDate(...args) {
// В TS:
// function createDate(timestamp: number): Date
// function createDate(month: number, day: number, year: number): Date
if (args.length === 1 && typeof args[0] === 'number') {
return new Date(args[0])
}
if (args.length === 3) {
const [month, day, year] = args
return new Date(year, month - 1, day)
}
throw new Error(`Неверные аргументы: ожидается (timestamp) или (month, day, year)`)
}
console.log('\n=== createDate ===')
console.log(createDate(0)) // Thu Jan 01 1970...
console.log(createDate(1, 15, 2024)) // Mon Jan 15 2024...
try {
createDate(1, 15) // В TS: ошибка — нет подходящей перегрузки
} catch (e) {
console.log(e.message)
}
// === Паттерн 3: parse строки и массива ===
function parse(input) {
// В TS:
// function parse(input: string): string[]
// function parse(input: string[]): string
if (typeof input === 'string') {
return input.split(',').map(s => s.trim())
}
if (Array.isArray(input)) {
return input.join(', ')
}
throw new TypeError(`Ожидается строка или массив строк`)
}
console.log('\n=== parse ===')
console.log(parse('red, green, blue')) // ['red', 'green', 'blue']
console.log(parse(['one', 'two', 'three'])) // 'one, two, three'
// === Паттерн 4: format числа и даты ===
function format(value, ...rest) {
// В TS:
// function format(value: number, digits: number): string
// function format(value: Date, locale: string): string
if (typeof value === 'number') {
const digits = rest[0] ?? 2
return value.toFixed(digits)
}
if (value instanceof Date) {
const locale = rest[0] ?? 'ru-RU'
return value.toLocaleDateString(locale)
}
throw new TypeError(`Ожидается число или дата`)
}
console.log('\n=== format ===')
console.log(format(3.14159, 2)) // '3.14'
console.log(format(1000, 0)) // '1000'
console.log(format(new Date('2024-01-15'), 'ru-RU')) // '15.01.2024'В TypeScript **function overloads** позволяют объявить несколько сигнатур для одной функции. Это нужно когда функция ведёт себя по-разному в зависимости от типов аргументов.
// Перегрузка: разные сигнатуры вызова
function createDate(timestamp: number): Date
function createDate(month: number, day: number, year: number): Date
// Реализация (не видна снаружи):
function createDate(monthOrTimestamp: number, day?: number, year?: number): Date {
if (day !== undefined && year !== undefined) {
return new Date(year, monthOrTimestamp - 1, day)
} else {
return new Date(monthOrTimestamp)
}
}
// Вызовы:
createDate(1609459200000) // OK — по timestamp
createDate(1, 15, 2024) // OK — месяц, день, год
createDate(15, 2024) // Ошибка TS: нет подходящей перегрузки// 1. Сигнатуры перегрузок (overload signatures) — только для TypeScript, не выполняются:
function reverse(str: string): string
function reverse(arr: number[]): number[]
// 2. Сигнатура реализации — должна быть совместима со всеми перегрузками:
function reverse(input: string | number[]): string | number[] {
if (typeof input === 'string') {
return input.split('').reverse().join('')
}
return [...input].reverse()
}
// TypeScript знает точные типы при вызове:
const str = reverse('hello') // тип: string
const arr = reverse([1, 2, 3]) // тип: number[]1. Должно быть **минимум 2 сигнатуры перегрузки**
2. Сигнатура реализации **не участвует** в разрешении перегрузки — она только реализует логику
3. Сигнатура реализации должна быть **совместима** со всеми перегрузками
4. Более **специфичные** сигнатуры должны идти **раньше** общих
// Плохо — менее специфичная сигнатура первой может затенить другие:
function format(value: string | number): string // слишком общая
function format(value: number, digits: number): string // никогда не выбирается!
// Хорошо — специфичные первыми:
function format(value: number, digits: number): string
function format(value: string | number): stringКлассический пример из DOM API:
// В TypeScript встроено (упрощённо):
function querySelector(selector: string): Element | null
function querySelector<T extends Element>(selector: string): T | null
// Реальный usecase:
const input = document.querySelector<HTMLInputElement>('#name')
// input: HTMLInputElement | nullИспользуй перегрузки когда:
Не используй когда:
string | numberfunction foo(a: string, b?: number)function identity<T>(x: T): T// Не нужна перегрузка — достаточно optional параметра:
function greet(name: string, greeting?: string): string {
return `${greeting ?? 'Привет'}, ${name}!`
}
// Нужна перегрузка — разные входные/выходные типы:
function parse(input: string): string[]
function parse(input: string[]): string
function parse(input: string | string[]): string | string[] {
if (typeof input === 'string') return input.split(',')
return input.join(',')
}Паттерны перегрузки функций в JavaScript: dispatch по типу аргументов
// В TS: function overloads — разные сигнатуры для одной функции
// В JS: реализуем через проверку типов аргументов
// === Паттерн 1: reverse для строк и массивов ===
function reverse(input) {
// В TS:
// function reverse(str: string): string
// function reverse(arr: number[]): number[]
if (typeof input === 'string') {
return input.split('').reverse().join('')
}
if (Array.isArray(input)) {
return [...input].reverse()
}
throw new TypeError(`Ожидается строка или массив, получено: ${typeof input}`)
}
console.log('=== reverse ===')
console.log(reverse('hello')) // 'olleh'
console.log(reverse('TypeScript')) // 'tpircSepyT'
console.log(reverse([1, 2, 3, 4])) // [4, 3, 2, 1]
console.log(reverse(['a', 'b', 'c'])) // ['c', 'b', 'a']
// === Паттерн 2: createDate — по timestamp или по дате ===
function createDate(...args) {
// В TS:
// function createDate(timestamp: number): Date
// function createDate(month: number, day: number, year: number): Date
if (args.length === 1 && typeof args[0] === 'number') {
return new Date(args[0])
}
if (args.length === 3) {
const [month, day, year] = args
return new Date(year, month - 1, day)
}
throw new Error(`Неверные аргументы: ожидается (timestamp) или (month, day, year)`)
}
console.log('\n=== createDate ===')
console.log(createDate(0)) // Thu Jan 01 1970...
console.log(createDate(1, 15, 2024)) // Mon Jan 15 2024...
try {
createDate(1, 15) // В TS: ошибка — нет подходящей перегрузки
} catch (e) {
console.log(e.message)
}
// === Паттерн 3: parse строки и массива ===
function parse(input) {
// В TS:
// function parse(input: string): string[]
// function parse(input: string[]): string
if (typeof input === 'string') {
return input.split(',').map(s => s.trim())
}
if (Array.isArray(input)) {
return input.join(', ')
}
throw new TypeError(`Ожидается строка или массив строк`)
}
console.log('\n=== parse ===')
console.log(parse('red, green, blue')) // ['red', 'green', 'blue']
console.log(parse(['one', 'two', 'three'])) // 'one, two, three'
// === Паттерн 4: format числа и даты ===
function format(value, ...rest) {
// В TS:
// function format(value: number, digits: number): string
// function format(value: Date, locale: string): string
if (typeof value === 'number') {
const digits = rest[0] ?? 2
return value.toFixed(digits)
}
if (value instanceof Date) {
const locale = rest[0] ?? 'ru-RU'
return value.toLocaleDateString(locale)
}
throw new TypeError(`Ожидается число или дата`)
}
console.log('\n=== format ===')
console.log(format(3.14159, 2)) // '3.14'
console.log(format(1000, 0)) // '1000'
console.log(format(new Date('2024-01-15'), 'ru-RU')) // '15.01.2024'Реализуй функцию `stringify(value)` с двумя режимами работы: если передан массив — вернуть строку элементов через " | " (например [1,2,3] -> "1 | 2 | 3"); если передан объект — вернуть строку пар ключ=значение через ", " (например {a:1,b:2} -> "a=1, b=2"); для других типов бросать TypeError.
Сначала проверяй Array.isArray(value) — это важно, так как typeof [] === "object". Потом проверяй объект: typeof value === "object" && value !== null. Используй Object.entries(value) для получения пар [ключ, значение] из объекта.
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке