// Явные аннотации параметров и возвращаемого типа
function add(a: number, b: number): number {
return a + b
}
// Стрелочная функция
const multiply = (a: number, b: number): number => a * b
// TypeScript выводит тип сам, если не указан явно
const divide = (a: number, b: number) => a / b // TypeScript выводит: number// Опциональный параметр — может быть undefined
function greet(name: string, greeting?: string): string {
return `${greeting ?? 'Привет'}, ${name}!`
}
// Default параметры — значение по умолчанию
function createUser(name: string, role: string = 'viewer'): User {
return { name, role }
}
greet('Алексей') // 'Привет, Алексей!'
greet('Алексей', 'Здрасте') // 'Здрасте, Алексей!'function sum(...numbers: number[]): number {
return numbers.reduce((acc, n) => acc + n, 0)
}
sum(1, 2, 3, 4, 5) // 15TypeScript позволяет описать несколько сигнатур для одной функции:
// Объявления перегрузок (только сигнатуры):
function format(value: string): string
function format(value: number): string
function format(value: Date): string
// Реализация (внутренняя, с union типом):
function format(value: string | number | Date): string {
if (typeof value === 'string') return value.toUpperCase()
if (typeof value === 'number') return value.toFixed(2)
return value.toLocaleDateString('ru-RU')
}Типы функций описывают сигнатуру как переменную:
// type alias для функции
type Callback = (err: Error | null, result: string) => void
type Predicate<T> = (item: T) => boolean
type Transform<A, B> = (input: A) => B
// Функция как параметр
function processItems(
items: string[],
filter: Predicate<string>,
transform: Transform<string, string>
): string[] {
return items.filter(filter).map(transform)
}Generics (обобщения) — функция работает с разными типами, сохраняя типобезопасность:
// T — параметр типа (type parameter)
function identity<T>(arg: T): T {
return arg
}
identity<string>('hello') // возвращает string
identity<number>(42) // возвращает number
identity('hello') // TypeScript выводит T = string автоматически
// Практичный пример:
function first<T>(arr: T[]): T | undefined {
return arr[0]
}
function map<T, U>(arr: T[], fn: (item: T) => U): U[] {
return arr.map(fn)
}
const lengths = map(['hello', 'world', 'hi'], s => s.length)
// TypeScript знает: lengths: number[]Классические функции функционального программирования — идеально подходят для дженериков:
// pipe применяет функции слева направо
function pipe<T>(...fns: Array<(x: T) => T>): (x: T) => T {
return (x) => fns.reduce((acc, fn) => fn(acc), x)
}
const process = pipe(
(x: number) => x * 2, // double
(x: number) => x + 1, // addOne
(x: number) => x ** 2, // square
)
process(3) // (3*2+1)^2 = 49Утилиты функционального программирования с runtime проверкой типов: pipe, compose, memoize, curry
// Реализация функциональных утилит с runtime-валидацией.
// В TypeScript типы гарантировали бы корректность при компиляции.
// pipe применяет функции слева направо: pipe(f, g, h)(x) = h(g(f(x)))
function pipe(...fns) {
if (fns.length === 0) return x => x // identity
if (!fns.every(f => typeof f === 'function')) {
throw new TypeError('pipe принимает только функции')
}
return function(x) {
return fns.reduce((acc, fn) => fn(acc), x)
}
}
// compose применяет функции справа налево: compose(f, g, h)(x) = f(g(h(x)))
function compose(...fns) {
return pipe(...fns.reverse())
}
// memoize кэширует результаты вызовов
function memoize(fn) {
if (typeof fn !== 'function') {
throw new TypeError('memoize принимает функцию')
}
const cache = new Map()
return function(...args) {
const key = JSON.stringify(args)
if (cache.has(key)) {
return cache.get(key)
}
const result = fn.apply(this, args)
cache.set(key, result)
return result
}
}
// curry превращает f(a, b, c) в f(a)(b)(c)
function curry(fn) {
if (typeof fn !== 'function') {
throw new TypeError('curry принимает функцию')
}
const arity = fn.length
return function curried(...args) {
if (args.length >= arity) {
return fn.apply(this, args)
}
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs))
}
}
}
// --- Демонстрация pipe ---
console.log('=== pipe ===')
const double = x => x * 2
const addOne = x => x + 1
const square = x => x ** 2
const negate = x => -x
const transform = pipe(double, addOne, square)
console.log(transform(3)) // (3*2+1)^2 = 49
console.log(transform(4)) // (4*2+1)^2 = 81
const stringPipeline = pipe(
s => s.trim(),
s => s.toLowerCase(),
s => s.replace(/\s+/g, '-'),
)
console.log(stringPipeline(' Hello World ')) // 'hello-world'
// --- Демонстрация compose ---
console.log('\n=== compose ===')
const processNum = compose(negate, square, addOne, double)
console.log(processNum(3)) // -(((3*2)+1)^2) = -49
// --- Демонстрация memoize ---
console.log('\n=== memoize ===')
let callCount = 0
const expensiveFn = memoize(n => {
callCount++
return n * n
})
console.log(expensiveFn(5)) // 25 (вычисляет)
console.log(expensiveFn(5)) // 25 (из кэша)
console.log(expensiveFn(6)) // 36 (вычисляет)
console.log(`Вызовов функции: ${callCount}`) // 2
// --- Демонстрация curry ---
console.log('\n=== curry ===')
const add = curry((a, b) => a + b)
const add5 = add(5)
console.log(add5(3)) // 8
console.log(add5(10)) // 15
console.log(add(2)(3)) // 5
const multiply = curry((a, b, c) => a * b * c)
console.log(multiply(2)(3)(4)) // 24
console.log(multiply(2, 3)(4)) // 24
console.log(multiply(2)(3, 4)) // 24// Явные аннотации параметров и возвращаемого типа
function add(a: number, b: number): number {
return a + b
}
// Стрелочная функция
const multiply = (a: number, b: number): number => a * b
// TypeScript выводит тип сам, если не указан явно
const divide = (a: number, b: number) => a / b // TypeScript выводит: number// Опциональный параметр — может быть undefined
function greet(name: string, greeting?: string): string {
return `${greeting ?? 'Привет'}, ${name}!`
}
// Default параметры — значение по умолчанию
function createUser(name: string, role: string = 'viewer'): User {
return { name, role }
}
greet('Алексей') // 'Привет, Алексей!'
greet('Алексей', 'Здрасте') // 'Здрасте, Алексей!'function sum(...numbers: number[]): number {
return numbers.reduce((acc, n) => acc + n, 0)
}
sum(1, 2, 3, 4, 5) // 15TypeScript позволяет описать несколько сигнатур для одной функции:
// Объявления перегрузок (только сигнатуры):
function format(value: string): string
function format(value: number): string
function format(value: Date): string
// Реализация (внутренняя, с union типом):
function format(value: string | number | Date): string {
if (typeof value === 'string') return value.toUpperCase()
if (typeof value === 'number') return value.toFixed(2)
return value.toLocaleDateString('ru-RU')
}Типы функций описывают сигнатуру как переменную:
// type alias для функции
type Callback = (err: Error | null, result: string) => void
type Predicate<T> = (item: T) => boolean
type Transform<A, B> = (input: A) => B
// Функция как параметр
function processItems(
items: string[],
filter: Predicate<string>,
transform: Transform<string, string>
): string[] {
return items.filter(filter).map(transform)
}Generics (обобщения) — функция работает с разными типами, сохраняя типобезопасность:
// T — параметр типа (type parameter)
function identity<T>(arg: T): T {
return arg
}
identity<string>('hello') // возвращает string
identity<number>(42) // возвращает number
identity('hello') // TypeScript выводит T = string автоматически
// Практичный пример:
function first<T>(arr: T[]): T | undefined {
return arr[0]
}
function map<T, U>(arr: T[], fn: (item: T) => U): U[] {
return arr.map(fn)
}
const lengths = map(['hello', 'world', 'hi'], s => s.length)
// TypeScript знает: lengths: number[]Классические функции функционального программирования — идеально подходят для дженериков:
// pipe применяет функции слева направо
function pipe<T>(...fns: Array<(x: T) => T>): (x: T) => T {
return (x) => fns.reduce((acc, fn) => fn(acc), x)
}
const process = pipe(
(x: number) => x * 2, // double
(x: number) => x + 1, // addOne
(x: number) => x ** 2, // square
)
process(3) // (3*2+1)^2 = 49Утилиты функционального программирования с runtime проверкой типов: pipe, compose, memoize, curry
// Реализация функциональных утилит с runtime-валидацией.
// В TypeScript типы гарантировали бы корректность при компиляции.
// pipe применяет функции слева направо: pipe(f, g, h)(x) = h(g(f(x)))
function pipe(...fns) {
if (fns.length === 0) return x => x // identity
if (!fns.every(f => typeof f === 'function')) {
throw new TypeError('pipe принимает только функции')
}
return function(x) {
return fns.reduce((acc, fn) => fn(acc), x)
}
}
// compose применяет функции справа налево: compose(f, g, h)(x) = f(g(h(x)))
function compose(...fns) {
return pipe(...fns.reverse())
}
// memoize кэширует результаты вызовов
function memoize(fn) {
if (typeof fn !== 'function') {
throw new TypeError('memoize принимает функцию')
}
const cache = new Map()
return function(...args) {
const key = JSON.stringify(args)
if (cache.has(key)) {
return cache.get(key)
}
const result = fn.apply(this, args)
cache.set(key, result)
return result
}
}
// curry превращает f(a, b, c) в f(a)(b)(c)
function curry(fn) {
if (typeof fn !== 'function') {
throw new TypeError('curry принимает функцию')
}
const arity = fn.length
return function curried(...args) {
if (args.length >= arity) {
return fn.apply(this, args)
}
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs))
}
}
}
// --- Демонстрация pipe ---
console.log('=== pipe ===')
const double = x => x * 2
const addOne = x => x + 1
const square = x => x ** 2
const negate = x => -x
const transform = pipe(double, addOne, square)
console.log(transform(3)) // (3*2+1)^2 = 49
console.log(transform(4)) // (4*2+1)^2 = 81
const stringPipeline = pipe(
s => s.trim(),
s => s.toLowerCase(),
s => s.replace(/\s+/g, '-'),
)
console.log(stringPipeline(' Hello World ')) // 'hello-world'
// --- Демонстрация compose ---
console.log('\n=== compose ===')
const processNum = compose(negate, square, addOne, double)
console.log(processNum(3)) // -(((3*2)+1)^2) = -49
// --- Демонстрация memoize ---
console.log('\n=== memoize ===')
let callCount = 0
const expensiveFn = memoize(n => {
callCount++
return n * n
})
console.log(expensiveFn(5)) // 25 (вычисляет)
console.log(expensiveFn(5)) // 25 (из кэша)
console.log(expensiveFn(6)) // 36 (вычисляет)
console.log(`Вызовов функции: ${callCount}`) // 2
// --- Демонстрация curry ---
console.log('\n=== curry ===')
const add = curry((a, b) => a + b)
const add5 = add(5)
console.log(add5(3)) // 8
console.log(add5(10)) // 15
console.log(add(2)(3)) // 5
const multiply = curry((a, b, c) => a * b * c)
console.log(multiply(2)(3)(4)) // 24
console.log(multiply(2, 3)(4)) // 24
console.log(multiply(2)(3, 4)) // 24Реализуй функцию `pipe(...fns)` которая принимает список функций и возвращает новую функцию, применяющую их последовательно слева направо. `pipe(double, addOne, square)(3)` должно вернуть 49: сначала double(3)=6, затем addOne(6)=7, затем square(7)=49.
Проверка: fns.every(f => typeof f === 'function'). Функция-идентичность: x => x. Внутри возвращаемой функции используй fns.reduce((acc, fn) => fn(acc), x) — reduce начинает с x и применяет каждую функцию к накопленному результату.
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке