Template Literal Types — это типы, созданные с помощью синтаксиса шаблонных строк. Они позволяют строить новые строковые типы путём комбинирования литеральных строковых типов.
type Greeting = `Hello, ${string}!`
// Любая строка вида "Hello, ...!"
type EventName = `on${string}`
// Любая строка начинающаяся с "on": 'onClick', 'onChange', ...Мощь template literal types раскрывается при комбинировании с union:
type Direction = 'top' | 'right' | 'bottom' | 'left'
type Property = 'margin' | 'padding'
type CSSProperty = `${Property}-${Direction}`
// type CSSProperty =
// | 'margin-top' | 'margin-right' | 'margin-bottom' | 'margin-left'
// | 'padding-top' | 'padding-right' | 'padding-bottom' | 'padding-left'
// TypeScript автоматически создаёт все комбинации!type ObjectKeys = 'name' | 'age' | 'email'
// Автоматически создаём обработчики событий:
type EventHandlers = {
[K in ObjectKeys as `on${Capitalize<K>}Change`]: (value: string) => void
}
// type EventHandlers = {
// onNameChange: (value: string) => void
// onAgeChange: (value: string) => void
// onEmailChange: (value: string) => void
// }TypeScript предоставляет 4 встроенных утилиты для работы со строковыми типами:
type S = 'hello world'
type Upper = Uppercase<S> // 'HELLO WORLD'
type Lower = Lowercase<'HELLO'> // 'hello'
type Cap = Capitalize<S> // 'Hello world' — первая буква в верхнем регистре
type Uncap = Uncapitalize<'Hello'> // 'hello' — первая буква в нижнем регистреОни особенно полезны в сочетании с template literal types:
type Getter<T extends string> = `get${Capitalize<T>}`
type NameGetter = Getter<'name'> // 'getName'
type AgeGetter = Getter<'age'> // 'getAge'
type EmailGetter = Getter<'email'> // 'getEmail'type Size = 'sm' | 'md' | 'lg' | 'xl'
type Color = 'primary' | 'secondary' | 'danger'
type ButtonClass = `btn-${Color}-${Size}`
// 'btn-primary-sm' | 'btn-primary-md' | ... | 'btn-danger-xl'
// 12 комбинаций автоматически!
function getButtonClass(color: Color, size: Size): ButtonClass {
return `btn-${color}-${size}`
}type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
type Resource = 'users' | 'posts' | 'comments'
type ApiEndpoint = `/api/${Resource}`
// '/api/users' | '/api/posts' | '/api/comments'
type ApiRoute = `${HttpMethod} /api/${Resource}`
// 'GET /api/users' | 'POST /api/users' | ... | 'DELETE /api/comments'
// 12 комбинацийС помощью infer (в conditional types) можно извлекать части строки:
type ExtractRoute<T extends string> =
T extends `GET /api/${infer R}` ? R : never
type Route = ExtractRoute<'GET /api/users'>
// type Route = 'users'Template literal типы в действии: генерация строк из комбинаций и утилиты строк
// В TS: Template Literal Types создают новые строковые типы
// В JS: показываем runtime-аналог — генерацию всех комбинаций
// === Генерация всех комбинаций (как TS template literal + union) ===
function generateCombinations(...arrays) {
// В TS: `${A}-${B}` где A и B — union types создаёт все комбинации
return arrays.reduce((acc, curr) =>
acc.flatMap(a => curr.map(b => `${a}-${b}`))
)
}
const properties = ['margin', 'padding']
const directions = ['top', 'right', 'bottom', 'left']
const cssProperties = generateCombinations(properties, directions)
console.log('=== CSS свойства (margin/padding + направления) ===')
console.log(cssProperties)
// ['margin-top', 'margin-right', ..., 'padding-left']
console.log(`Всего: ${cssProperties.length} свойств`) // 8
// === Capitalize утилита (как TS Capitalize<string>) ===
function capitalize(str) {
// В TS: Capitalize<'hello'> = 'Hello'
return str.charAt(0).toUpperCase() + str.slice(1)
}
// === Паттерн: генераторы getter/setter имён ===
console.log('\n=== Getters/Setters (Capitalize + template) ===')
const fields = ['name', 'age', 'email', 'status']
const methods = fields.flatMap(field => [
// В TS: `get${Capitalize<K>}` и `set${Capitalize<K>}`
`get${capitalize(field)}`,
`set${capitalize(field)}`,
])
console.log(methods)
// ['getName', 'setName', 'getAge', 'setAge', 'getEmail', 'setEmail', ...]
// === Паттерн: типизированные event handlers ===
console.log('\n=== Event handlers (on + Capitalize + Change) ===')
function createEventHandlers(fields) {
// В TS: { [K in Fields as `on${Capitalize<K>}Change`]: handler }
const handlers = {}
fields.forEach(field => {
const eventName = `on${capitalize(field)}Change`
handlers[eventName] = (value) => {
console.log(`${field} изменён на: ${value}`)
}
})
return handlers
}
const handlers = createEventHandlers(['name', 'age', 'email'])
console.log('Созданные обработчики:', Object.keys(handlers))
// ['onNameChange', 'onAgeChange', 'onEmailChange']
handlers.onNameChange('Алексей') // 'name изменён на: Алексей'
handlers.onAgeChange(28) // 'age изменён на: 28'
// === Паттерн: строгие API маршруты ===
console.log('\n=== API маршруты ===')
const methods2 = ['GET', 'POST', 'PUT', 'DELETE']
const resources = ['users', 'posts', 'comments']
// В TS: type ApiRoute = `${HttpMethod} /api/${Resource}`
const routes = generateCombinations(methods2, resources.map(r => `/api/${r}`))
console.log('Все API маршруты:', routes)
// ['GET-/api/users', 'GET-/api/posts', ..., 'DELETE-/api/comments']
// (12 комбинаций)Template Literal Types — это типы, созданные с помощью синтаксиса шаблонных строк. Они позволяют строить новые строковые типы путём комбинирования литеральных строковых типов.
type Greeting = `Hello, ${string}!`
// Любая строка вида "Hello, ...!"
type EventName = `on${string}`
// Любая строка начинающаяся с "on": 'onClick', 'onChange', ...Мощь template literal types раскрывается при комбинировании с union:
type Direction = 'top' | 'right' | 'bottom' | 'left'
type Property = 'margin' | 'padding'
type CSSProperty = `${Property}-${Direction}`
// type CSSProperty =
// | 'margin-top' | 'margin-right' | 'margin-bottom' | 'margin-left'
// | 'padding-top' | 'padding-right' | 'padding-bottom' | 'padding-left'
// TypeScript автоматически создаёт все комбинации!type ObjectKeys = 'name' | 'age' | 'email'
// Автоматически создаём обработчики событий:
type EventHandlers = {
[K in ObjectKeys as `on${Capitalize<K>}Change`]: (value: string) => void
}
// type EventHandlers = {
// onNameChange: (value: string) => void
// onAgeChange: (value: string) => void
// onEmailChange: (value: string) => void
// }TypeScript предоставляет 4 встроенных утилиты для работы со строковыми типами:
type S = 'hello world'
type Upper = Uppercase<S> // 'HELLO WORLD'
type Lower = Lowercase<'HELLO'> // 'hello'
type Cap = Capitalize<S> // 'Hello world' — первая буква в верхнем регистре
type Uncap = Uncapitalize<'Hello'> // 'hello' — первая буква в нижнем регистреОни особенно полезны в сочетании с template literal types:
type Getter<T extends string> = `get${Capitalize<T>}`
type NameGetter = Getter<'name'> // 'getName'
type AgeGetter = Getter<'age'> // 'getAge'
type EmailGetter = Getter<'email'> // 'getEmail'type Size = 'sm' | 'md' | 'lg' | 'xl'
type Color = 'primary' | 'secondary' | 'danger'
type ButtonClass = `btn-${Color}-${Size}`
// 'btn-primary-sm' | 'btn-primary-md' | ... | 'btn-danger-xl'
// 12 комбинаций автоматически!
function getButtonClass(color: Color, size: Size): ButtonClass {
return `btn-${color}-${size}`
}type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
type Resource = 'users' | 'posts' | 'comments'
type ApiEndpoint = `/api/${Resource}`
// '/api/users' | '/api/posts' | '/api/comments'
type ApiRoute = `${HttpMethod} /api/${Resource}`
// 'GET /api/users' | 'POST /api/users' | ... | 'DELETE /api/comments'
// 12 комбинацийС помощью infer (в conditional types) можно извлекать части строки:
type ExtractRoute<T extends string> =
T extends `GET /api/${infer R}` ? R : never
type Route = ExtractRoute<'GET /api/users'>
// type Route = 'users'Template literal типы в действии: генерация строк из комбинаций и утилиты строк
// В TS: Template Literal Types создают новые строковые типы
// В JS: показываем runtime-аналог — генерацию всех комбинаций
// === Генерация всех комбинаций (как TS template literal + union) ===
function generateCombinations(...arrays) {
// В TS: `${A}-${B}` где A и B — union types создаёт все комбинации
return arrays.reduce((acc, curr) =>
acc.flatMap(a => curr.map(b => `${a}-${b}`))
)
}
const properties = ['margin', 'padding']
const directions = ['top', 'right', 'bottom', 'left']
const cssProperties = generateCombinations(properties, directions)
console.log('=== CSS свойства (margin/padding + направления) ===')
console.log(cssProperties)
// ['margin-top', 'margin-right', ..., 'padding-left']
console.log(`Всего: ${cssProperties.length} свойств`) // 8
// === Capitalize утилита (как TS Capitalize<string>) ===
function capitalize(str) {
// В TS: Capitalize<'hello'> = 'Hello'
return str.charAt(0).toUpperCase() + str.slice(1)
}
// === Паттерн: генераторы getter/setter имён ===
console.log('\n=== Getters/Setters (Capitalize + template) ===')
const fields = ['name', 'age', 'email', 'status']
const methods = fields.flatMap(field => [
// В TS: `get${Capitalize<K>}` и `set${Capitalize<K>}`
`get${capitalize(field)}`,
`set${capitalize(field)}`,
])
console.log(methods)
// ['getName', 'setName', 'getAge', 'setAge', 'getEmail', 'setEmail', ...]
// === Паттерн: типизированные event handlers ===
console.log('\n=== Event handlers (on + Capitalize + Change) ===')
function createEventHandlers(fields) {
// В TS: { [K in Fields as `on${Capitalize<K>}Change`]: handler }
const handlers = {}
fields.forEach(field => {
const eventName = `on${capitalize(field)}Change`
handlers[eventName] = (value) => {
console.log(`${field} изменён на: ${value}`)
}
})
return handlers
}
const handlers = createEventHandlers(['name', 'age', 'email'])
console.log('Созданные обработчики:', Object.keys(handlers))
// ['onNameChange', 'onAgeChange', 'onEmailChange']
handlers.onNameChange('Алексей') // 'name изменён на: Алексей'
handlers.onAgeChange(28) // 'age изменён на: 28'
// === Паттерн: строгие API маршруты ===
console.log('\n=== API маршруты ===')
const methods2 = ['GET', 'POST', 'PUT', 'DELETE']
const resources = ['users', 'posts', 'comments']
// В TS: type ApiRoute = `${HttpMethod} /api/${Resource}`
const routes = generateCombinations(methods2, resources.map(r => `/api/${r}`))
console.log('Все API маршруты:', routes)
// ['GET-/api/users', 'GET-/api/posts', ..., 'DELETE-/api/comments']
// (12 комбинаций)Реализуй функцию `createModel(fields)`, которая принимает массив имён полей и возвращает объект с методами get/set для каждого поля. Имена методов должны быть в формате getName, setName (с заглавной первой буквой поля). Каждый setter должен сохранять значение, каждый getter — возвращать его.
capitalize: str.charAt(0).toUpperCase() + str.slice(1). Для getter: const getterName = `get${capitalize(field)}`; model[getterName] = () => store[field]. Для setter: const setterName = `set${capitalize(field)}`; model[setterName] = (value) => { store[field] = value }.
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке