В JavaScript typeof — это runtime-оператор для проверки типа значения. В TypeScript typeof **дополнительно** работает на уровне типов: он позволяет получить **тип переменной или функции**.
// JavaScript typeof (runtime):
typeof 'hello' // 'string'
typeof 42 // 'number'
// TypeScript typeof (на уровне типов):
const config = {
host: 'localhost',
port: 3000,
debug: true,
}
type Config = typeof config
// type Config = {
// host: string
// port: number
// debug: boolean
// }
// Тип функции:
function add(a: number, b: number): number {
return a + b
}
type AddFn = typeof add
// type AddFn = (a: number, b: number) => numberОсновной сценарий: у тебя есть значение (константа, объект, функция), и ты хочешь использовать его тип **без повторного написания**:
// Без typeof — дублирование:
interface Config {
host: string
port: number
}
const config: Config = { host: 'localhost', port: 3000 }
// С typeof — тип выводится из значения:
const config = { host: 'localhost', port: 3000 }
type Config = typeof config // Автоматически: { host: string; port: number }
// Особенно полезно с as const:
const COLORS = { RED: 'red', GREEN: 'green', BLUE: 'blue' } as const
type Colors = typeof COLORS
// type Colors = { readonly RED: 'red'; readonly GREEN: 'green'; readonly BLUE: 'blue' }keyof T возвращает **объединение** (union) строковых литеральных типов всех ключей типа T:
interface User {
id: number
name: string
email: string
}
type UserKeys = keyof User
// type UserKeys = 'id' | 'name' | 'email'
// Использование keyof для строгой типизации:
function getField(user: User, field: keyof User): string | number {
return user[field]
}
getField(user, 'name') // OK
getField(user, 'id') // OK
getField(user, 'phone') // Ошибка TS: 'phone' не в keyof UserВместе они позволяют работать с ключами **значений** (не только интерфейсов):
const defaultSettings = {
theme: 'dark',
language: 'ru',
fontSize: 14,
notifications: true,
}
type SettingsKey = keyof typeof defaultSettings
// type SettingsKey = 'theme' | 'language' | 'fontSize' | 'notifications'
function updateSetting(
settings: typeof defaultSettings,
key: keyof typeof defaultSettings,
value: typeof defaultSettings[keyof typeof defaultSettings]
) {
return { ...settings, [key]: value }
}function createUser(name: string, age: number) {
return { id: Math.random(), name, age, createdAt: new Date() }
}
// Тип возвращаемого значения функции:
type User = ReturnType<typeof createUser>
// type User = { id: number; name: string; age: number; createdAt: Date }
// Параметры функции:
type CreateUserParams = Parameters<typeof createUser>
// type CreateUserParams = [name: string, age: number]typeof и keyof паттерны в JavaScript: работа с ключами объектов и типобезопасный доступ
// В TS: typeof obj даёт тип объекта, keyof T даёт union ключей
// В JS: Object.keys() — runtime аналог keyof typeof obj
const defaultSettings = {
theme: 'dark',
language: 'ru',
fontSize: 14,
notifications: true,
}
// === keyof typeof: получение ключей объекта ===
console.log('=== Ключи объекта (keyof typeof) ===')
// В TS: type SettingsKey = keyof typeof defaultSettings = 'theme' | 'language' | ...
const settingsKeys = Object.keys(defaultSettings)
console.log('Допустимые ключи:', settingsKeys)
// ['theme', 'language', 'fontSize', 'notifications']
// === Типобезопасный getProperty (typeof + keyof) ===
function getProperty(obj, key) {
// В TS: function getProperty<T>(obj: T, key: keyof T): T[keyof T]
const validKeys = Object.keys(obj)
if (!validKeys.includes(key)) {
throw new Error(`Недопустимый ключ: '${key}'. Допустимые: ${validKeys.join(', ')}`)
}
return obj[key]
}
console.log('\n=== getProperty ===')
console.log(getProperty(defaultSettings, 'theme')) // 'dark'
console.log(getProperty(defaultSettings, 'fontSize')) // 14
try {
getProperty(defaultSettings, 'color') // В TS: ошибка компиляции через keyof
} catch (e) {
console.log(e.message) // 'Недопустимый ключ: color. ...'
}
// === updateSetting: typeof + keyof для patch объекта ===
function updateSetting(settings, key, value) {
const validKeys = Object.keys(settings)
if (!validKeys.includes(key)) {
throw new Error(`Ключ '${key}' не существует в настройках`)
}
return { ...settings, [key]: value }
}
console.log('\n=== updateSetting ===')
const updated1 = updateSetting(defaultSettings, 'theme', 'light')
console.log(updated1.theme) // 'light'
console.log(updated1.language) // 'ru' — остальные поля не изменились
const updated2 = updateSetting(defaultSettings, 'fontSize', 16)
console.log(updated2.fontSize) // 16
// === ReturnType паттерн: тип из функции ===
console.log('\n=== typeof function (ReturnType паттерн) ===')
function createUser(name, age) {
// В TS: ReturnType<typeof createUser> даёт тип этого объекта
return { id: Math.floor(Math.random() * 1000), name, age, createdAt: new Date().toISOString() }
}
const user = createUser('Алексей', 30)
console.log(user) // { id: ..., name: 'Алексей', age: 30, createdAt: '...' }
// Проверяем ключи созданного объекта:
const userKeys = Object.keys(user)
console.log('Ключи пользователя:', userKeys) // ['id', 'name', 'age', 'createdAt']
// === Перебор всех ключей с типами значений ===
console.log('\n=== Перебор ключей и типов ===')
Object.entries(defaultSettings).forEach(([key, value]) => {
// В TS: key: keyof typeof defaultSettings, value: typeof defaultSettings[key]
console.log(`${key}: ${typeof value} = ${value}`)
})В JavaScript typeof — это runtime-оператор для проверки типа значения. В TypeScript typeof **дополнительно** работает на уровне типов: он позволяет получить **тип переменной или функции**.
// JavaScript typeof (runtime):
typeof 'hello' // 'string'
typeof 42 // 'number'
// TypeScript typeof (на уровне типов):
const config = {
host: 'localhost',
port: 3000,
debug: true,
}
type Config = typeof config
// type Config = {
// host: string
// port: number
// debug: boolean
// }
// Тип функции:
function add(a: number, b: number): number {
return a + b
}
type AddFn = typeof add
// type AddFn = (a: number, b: number) => numberОсновной сценарий: у тебя есть значение (константа, объект, функция), и ты хочешь использовать его тип **без повторного написания**:
// Без typeof — дублирование:
interface Config {
host: string
port: number
}
const config: Config = { host: 'localhost', port: 3000 }
// С typeof — тип выводится из значения:
const config = { host: 'localhost', port: 3000 }
type Config = typeof config // Автоматически: { host: string; port: number }
// Особенно полезно с as const:
const COLORS = { RED: 'red', GREEN: 'green', BLUE: 'blue' } as const
type Colors = typeof COLORS
// type Colors = { readonly RED: 'red'; readonly GREEN: 'green'; readonly BLUE: 'blue' }keyof T возвращает **объединение** (union) строковых литеральных типов всех ключей типа T:
interface User {
id: number
name: string
email: string
}
type UserKeys = keyof User
// type UserKeys = 'id' | 'name' | 'email'
// Использование keyof для строгой типизации:
function getField(user: User, field: keyof User): string | number {
return user[field]
}
getField(user, 'name') // OK
getField(user, 'id') // OK
getField(user, 'phone') // Ошибка TS: 'phone' не в keyof UserВместе они позволяют работать с ключами **значений** (не только интерфейсов):
const defaultSettings = {
theme: 'dark',
language: 'ru',
fontSize: 14,
notifications: true,
}
type SettingsKey = keyof typeof defaultSettings
// type SettingsKey = 'theme' | 'language' | 'fontSize' | 'notifications'
function updateSetting(
settings: typeof defaultSettings,
key: keyof typeof defaultSettings,
value: typeof defaultSettings[keyof typeof defaultSettings]
) {
return { ...settings, [key]: value }
}function createUser(name: string, age: number) {
return { id: Math.random(), name, age, createdAt: new Date() }
}
// Тип возвращаемого значения функции:
type User = ReturnType<typeof createUser>
// type User = { id: number; name: string; age: number; createdAt: Date }
// Параметры функции:
type CreateUserParams = Parameters<typeof createUser>
// type CreateUserParams = [name: string, age: number]typeof и keyof паттерны в JavaScript: работа с ключами объектов и типобезопасный доступ
// В TS: typeof obj даёт тип объекта, keyof T даёт union ключей
// В JS: Object.keys() — runtime аналог keyof typeof obj
const defaultSettings = {
theme: 'dark',
language: 'ru',
fontSize: 14,
notifications: true,
}
// === keyof typeof: получение ключей объекта ===
console.log('=== Ключи объекта (keyof typeof) ===')
// В TS: type SettingsKey = keyof typeof defaultSettings = 'theme' | 'language' | ...
const settingsKeys = Object.keys(defaultSettings)
console.log('Допустимые ключи:', settingsKeys)
// ['theme', 'language', 'fontSize', 'notifications']
// === Типобезопасный getProperty (typeof + keyof) ===
function getProperty(obj, key) {
// В TS: function getProperty<T>(obj: T, key: keyof T): T[keyof T]
const validKeys = Object.keys(obj)
if (!validKeys.includes(key)) {
throw new Error(`Недопустимый ключ: '${key}'. Допустимые: ${validKeys.join(', ')}`)
}
return obj[key]
}
console.log('\n=== getProperty ===')
console.log(getProperty(defaultSettings, 'theme')) // 'dark'
console.log(getProperty(defaultSettings, 'fontSize')) // 14
try {
getProperty(defaultSettings, 'color') // В TS: ошибка компиляции через keyof
} catch (e) {
console.log(e.message) // 'Недопустимый ключ: color. ...'
}
// === updateSetting: typeof + keyof для patch объекта ===
function updateSetting(settings, key, value) {
const validKeys = Object.keys(settings)
if (!validKeys.includes(key)) {
throw new Error(`Ключ '${key}' не существует в настройках`)
}
return { ...settings, [key]: value }
}
console.log('\n=== updateSetting ===')
const updated1 = updateSetting(defaultSettings, 'theme', 'light')
console.log(updated1.theme) // 'light'
console.log(updated1.language) // 'ru' — остальные поля не изменились
const updated2 = updateSetting(defaultSettings, 'fontSize', 16)
console.log(updated2.fontSize) // 16
// === ReturnType паттерн: тип из функции ===
console.log('\n=== typeof function (ReturnType паттерн) ===')
function createUser(name, age) {
// В TS: ReturnType<typeof createUser> даёт тип этого объекта
return { id: Math.floor(Math.random() * 1000), name, age, createdAt: new Date().toISOString() }
}
const user = createUser('Алексей', 30)
console.log(user) // { id: ..., name: 'Алексей', age: 30, createdAt: '...' }
// Проверяем ключи созданного объекта:
const userKeys = Object.keys(user)
console.log('Ключи пользователя:', userKeys) // ['id', 'name', 'age', 'createdAt']
// === Перебор всех ключей с типами значений ===
console.log('\n=== Перебор ключей и типов ===')
Object.entries(defaultSettings).forEach(([key, value]) => {
// В TS: key: keyof typeof defaultSettings, value: typeof defaultSettings[key]
console.log(`${key}: ${typeof value} = ${value}`)
})Реализуй функцию `strictPick(obj, keys)`, которая возвращает новый объект только с указанными ключами. Если какой-то ключ из keys не существует в obj — бросать ошибку. В TypeScript это выражается через keyof typeof obj. Проверяй каждый ключ перед копированием.
Используй for...of для перебора keys. Для проверки существования ключа — оператор in: if (!(key in obj)) throw new Error(...). Для создания результата используй reduce: keys.reduce((result, key) => { result[key] = obj[key]; return result }, {}).
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке