Namespace (пространство имён) — способ группировки связанного кода под единым именем, предотвращающий конфликты имён. В TypeScript namespace компилируется в IIFE-паттерн (Immediately Invoked Function Expression).
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean
}
export class LettersOnlyValidator implements StringValidator {
isValid(s: string): boolean {
return /^[A-Za-z]+$/.test(s)
}
}
export class NumberValidator implements StringValidator {
isValid(s: string): boolean {
return /^d+$/.test(s)
}
}
}
// Использование через точечную нотацию:
const validator = new Validation.LettersOnlyValidator()
console.log(validator.isValid('Hello')) // trueTypeScript компилирует namespace в IIFE:
// Скомпилированный вывод:
var Validation;
(function (Validation) {
class LettersOnlyValidator {
isValid(s) { return /^[A-Za-z]+$/.test(s) }
}
Validation.LettersOnlyValidator = LettersOnlyValidator
})(Validation || (Validation = {}))namespace App {
export namespace Models {
export interface User {
id: number
name: string
}
export interface Product {
id: number
price: number
}
}
export namespace Services {
export class UserService {
private users: Models.User[] = []
add(user: Models.User): void {
this.users.push(user)
}
findById(id: number): Models.User | undefined {
return this.users.find(u => u.id === id)
}
}
}
}
const service = new App.Services.UserService()
service.add({ id: 1, name: 'Алексей' })import UserService = App.Services.UserService
import User = App.Models.User
const svc = new UserService() // не нужно писать App.Services.UserService| | Namespace | Module (ES Module) |
|---|---|---|
| Синтаксис | namespace Foo { } | export / import |
| Применение | Один файл или /// <reference> | Отдельные файлы |
| Рекомендуется | В .d.ts файлах | В современном коде |
| Tree-shaking | Нет | Да |
**Современная практика**: для нового кода используйте ES-модули (import/export). Namespace остался актуален для:
1. Файлов объявлений (.d.ts) — описание глобальных библиотек
2. Augmentation глобальных типов
3. Организации типов внутри одного .d.ts файла
// Типичное использование: глобальная библиотека (jQuery, _)
// jquery.d.ts
declare namespace jQuery {
function ajax(url: string, settings?: JQueryAjaxSettings): void
function get(url: string): JQueryXHR
interface JQueryAjaxSettings {
method?: string
data?: any
}
interface JQueryXHR {
done(callback: (data: any) => void): JQueryXHR
fail(callback: (error: any) => void): JQueryXHR
}
}
// Использование:
jQuery.ajax('/api/users')IIFE-паттерн как аналог namespace: группировка кода без загрязнения глобального пространства имён
// TypeScript namespace компилируется в IIFE-паттерн.
// Покажем тот же паттерн в чистом JavaScript.
// Аналог namespace Validation { ... }
const Validation = (function() {
// Приватные утилиты (не экспортируются)
function escapeRegex(s) {
return s.split('').map(function(c) {
var specials = ['.', '+', '?', '^', '$', '{', '}', '(', ')', '|', '[', ']']
return specials.indexOf(c) >= 0 ? '_' + c : c
}).join('')
}
// Публичные (аналог export в namespace)
class LettersOnlyValidator {
isValid(s) { return /^[A-Za-zА-Яа-яЁё]+$/u.test(s) }
get description() { return 'только буквы' }
}
class EmailValidator {
isValid(s) { return /^[^s@]+@[^s@]+.[^s@]+$/.test(s) }
get description() { return 'email адрес' }
}
class RangeValidator {
constructor(min, max) {
this.min = min
this.max = max
}
isValid(n) {
return typeof n === 'number' && n >= this.min && n <= this.max
}
get description() { return `число от ${this.min} до ${this.max}` }
}
function createPatternValidator(pattern, description) {
return {
isValid: (s) => pattern.test(s),
description,
}
}
return {
LettersOnlyValidator,
EmailValidator,
RangeValidator,
createPatternValidator,
}
})()
// Аналог вложенного namespace App.Models, App.Services
const App = (function() {
// namespace Models
const Models = Object.freeze({
createUser(id, name, email) {
return Object.freeze({ id, name, email, createdAt: new Date() })
},
createProduct(id, name, price) {
if (price < 0) throw new RangeError('Цена не может быть отрицательной')
return Object.freeze({ id, name, price })
},
})
// namespace Services
const Services = (function() {
class UserService {
#users = new Map()
add(user) {
if (this.#users.has(user.id)) {
throw new Error(`Пользователь с id=${user.id} уже существует`)
}
this.#users.set(user.id, user)
return this
}
findById(id) {
return this.#users.get(id) ?? null
}
findAll() {
return [...this.#users.values()]
}
get count() { return this.#users.size }
}
class ProductService {
#products = []
add(product) {
this.#products.push(product)
return this
}
findByPriceRange(min, max) {
return this.#products.filter(p => p.price >= min && p.price <= max)
}
get count() { return this.#products.length }
}
return { UserService, ProductService }
})()
return { Models, Services }
})()
// --- Демонстрация ---
console.log('=== Validation namespace ===')
const emailValidator = new Validation.EmailValidator()
const letterValidator = new Validation.LettersOnlyValidator()
const ageValidator = new Validation.RangeValidator(0, 150)
const testCases = [
{ value: 'user@example.com', validator: emailValidator },
{ value: 'not-an-email', validator: emailValidator },
{ value: 'Алексей', validator: letterValidator },
{ value: 'Alex123', validator: letterValidator },
{ value: 25, validator: ageValidator },
{ value: 200, validator: ageValidator },
]
testCases.forEach(({ value, validator }) => {
const result = validator.isValid(value) ? 'OK' : 'ОШИБКА'
console.log(`${result}: "${value}" (${validator.description})`)
})
console.log('\n=== App.Models namespace ===')
const user = App.Models.createUser(1, 'Алексей', 'alex@mail.ru')
const product = App.Models.createProduct(1, 'Ноутбук', 50000)
console.log('User:', user)
console.log('Product:', product)
console.log('\n=== App.Services namespace ===')
const userSvc = new App.Services.UserService()
userSvc.add(user)
.add(App.Models.createUser(2, 'Ольга', 'olga@mail.ru'))
console.log('Пользователей:', userSvc.count)
console.log('Найден:', userSvc.findById(1)?.name)
console.log('Все:', userSvc.findAll().map(u => u.name))
const productSvc = new App.Services.ProductService()
productSvc.add(product)
.add(App.Models.createProduct(2, 'Телефон', 25000))
.add(App.Models.createProduct(3, 'Планшет', 35000))
const affordable = productSvc.findByPriceRange(20000, 40000)
console.log('\nТовары 20к-40к:', affordable.map(p => p.name))Namespace (пространство имён) — способ группировки связанного кода под единым именем, предотвращающий конфликты имён. В TypeScript namespace компилируется в IIFE-паттерн (Immediately Invoked Function Expression).
namespace Validation {
export interface StringValidator {
isValid(s: string): boolean
}
export class LettersOnlyValidator implements StringValidator {
isValid(s: string): boolean {
return /^[A-Za-z]+$/.test(s)
}
}
export class NumberValidator implements StringValidator {
isValid(s: string): boolean {
return /^d+$/.test(s)
}
}
}
// Использование через точечную нотацию:
const validator = new Validation.LettersOnlyValidator()
console.log(validator.isValid('Hello')) // trueTypeScript компилирует namespace в IIFE:
// Скомпилированный вывод:
var Validation;
(function (Validation) {
class LettersOnlyValidator {
isValid(s) { return /^[A-Za-z]+$/.test(s) }
}
Validation.LettersOnlyValidator = LettersOnlyValidator
})(Validation || (Validation = {}))namespace App {
export namespace Models {
export interface User {
id: number
name: string
}
export interface Product {
id: number
price: number
}
}
export namespace Services {
export class UserService {
private users: Models.User[] = []
add(user: Models.User): void {
this.users.push(user)
}
findById(id: number): Models.User | undefined {
return this.users.find(u => u.id === id)
}
}
}
}
const service = new App.Services.UserService()
service.add({ id: 1, name: 'Алексей' })import UserService = App.Services.UserService
import User = App.Models.User
const svc = new UserService() // не нужно писать App.Services.UserService| | Namespace | Module (ES Module) |
|---|---|---|
| Синтаксис | namespace Foo { } | export / import |
| Применение | Один файл или /// <reference> | Отдельные файлы |
| Рекомендуется | В .d.ts файлах | В современном коде |
| Tree-shaking | Нет | Да |
**Современная практика**: для нового кода используйте ES-модули (import/export). Namespace остался актуален для:
1. Файлов объявлений (.d.ts) — описание глобальных библиотек
2. Augmentation глобальных типов
3. Организации типов внутри одного .d.ts файла
// Типичное использование: глобальная библиотека (jQuery, _)
// jquery.d.ts
declare namespace jQuery {
function ajax(url: string, settings?: JQueryAjaxSettings): void
function get(url: string): JQueryXHR
interface JQueryAjaxSettings {
method?: string
data?: any
}
interface JQueryXHR {
done(callback: (data: any) => void): JQueryXHR
fail(callback: (error: any) => void): JQueryXHR
}
}
// Использование:
jQuery.ajax('/api/users')IIFE-паттерн как аналог namespace: группировка кода без загрязнения глобального пространства имён
// TypeScript namespace компилируется в IIFE-паттерн.
// Покажем тот же паттерн в чистом JavaScript.
// Аналог namespace Validation { ... }
const Validation = (function() {
// Приватные утилиты (не экспортируются)
function escapeRegex(s) {
return s.split('').map(function(c) {
var specials = ['.', '+', '?', '^', '$', '{', '}', '(', ')', '|', '[', ']']
return specials.indexOf(c) >= 0 ? '_' + c : c
}).join('')
}
// Публичные (аналог export в namespace)
class LettersOnlyValidator {
isValid(s) { return /^[A-Za-zА-Яа-яЁё]+$/u.test(s) }
get description() { return 'только буквы' }
}
class EmailValidator {
isValid(s) { return /^[^s@]+@[^s@]+.[^s@]+$/.test(s) }
get description() { return 'email адрес' }
}
class RangeValidator {
constructor(min, max) {
this.min = min
this.max = max
}
isValid(n) {
return typeof n === 'number' && n >= this.min && n <= this.max
}
get description() { return `число от ${this.min} до ${this.max}` }
}
function createPatternValidator(pattern, description) {
return {
isValid: (s) => pattern.test(s),
description,
}
}
return {
LettersOnlyValidator,
EmailValidator,
RangeValidator,
createPatternValidator,
}
})()
// Аналог вложенного namespace App.Models, App.Services
const App = (function() {
// namespace Models
const Models = Object.freeze({
createUser(id, name, email) {
return Object.freeze({ id, name, email, createdAt: new Date() })
},
createProduct(id, name, price) {
if (price < 0) throw new RangeError('Цена не может быть отрицательной')
return Object.freeze({ id, name, price })
},
})
// namespace Services
const Services = (function() {
class UserService {
#users = new Map()
add(user) {
if (this.#users.has(user.id)) {
throw new Error(`Пользователь с id=${user.id} уже существует`)
}
this.#users.set(user.id, user)
return this
}
findById(id) {
return this.#users.get(id) ?? null
}
findAll() {
return [...this.#users.values()]
}
get count() { return this.#users.size }
}
class ProductService {
#products = []
add(product) {
this.#products.push(product)
return this
}
findByPriceRange(min, max) {
return this.#products.filter(p => p.price >= min && p.price <= max)
}
get count() { return this.#products.length }
}
return { UserService, ProductService }
})()
return { Models, Services }
})()
// --- Демонстрация ---
console.log('=== Validation namespace ===')
const emailValidator = new Validation.EmailValidator()
const letterValidator = new Validation.LettersOnlyValidator()
const ageValidator = new Validation.RangeValidator(0, 150)
const testCases = [
{ value: 'user@example.com', validator: emailValidator },
{ value: 'not-an-email', validator: emailValidator },
{ value: 'Алексей', validator: letterValidator },
{ value: 'Alex123', validator: letterValidator },
{ value: 25, validator: ageValidator },
{ value: 200, validator: ageValidator },
]
testCases.forEach(({ value, validator }) => {
const result = validator.isValid(value) ? 'OK' : 'ОШИБКА'
console.log(`${result}: "${value}" (${validator.description})`)
})
console.log('\n=== App.Models namespace ===')
const user = App.Models.createUser(1, 'Алексей', 'alex@mail.ru')
const product = App.Models.createProduct(1, 'Ноутбук', 50000)
console.log('User:', user)
console.log('Product:', product)
console.log('\n=== App.Services namespace ===')
const userSvc = new App.Services.UserService()
userSvc.add(user)
.add(App.Models.createUser(2, 'Ольга', 'olga@mail.ru'))
console.log('Пользователей:', userSvc.count)
console.log('Найден:', userSvc.findById(1)?.name)
console.log('Все:', userSvc.findAll().map(u => u.name))
const productSvc = new App.Services.ProductService()
productSvc.add(product)
.add(App.Models.createProduct(2, 'Телефон', 25000))
.add(App.Models.createProduct(3, 'Планшет', 35000))
const affordable = productSvc.findByPriceRange(20000, 40000)
console.log('\nТовары 20к-40к:', affordable.map(p => p.name))Реализуй объект-namespace `MathUtils` через IIFE. Он должен содержать: `clamp(value, min, max)` — ограничивает значение диапазоном [min, max]; `lerp(a, b, t)` — линейная интерполяция между a и b при t ∈ [0, 1] (формула: a + (b - a) * t); `roundTo(value, decimals)` — округляет до указанного количества знаков после запятой; `randomInt(min, max)` — возвращает случайное целое число в диапазоне [min, max] включительно.
clamp: return Math.min(Math.max(value, min), max). lerp: return a + (b - a) * t. roundTo: const factor = 10 ** decimals; return Math.round(value * factor) / factor. randomInt: return Math.floor(Math.random() * (max - min + 1)) + min.
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке