Типы функций и классов
Типы функций и классов
Эта группа утилитарных типов позволяет извлекать типовую информацию из сигнатур функций и конструкторов. Они построены на infer и условных типах.
Parameters<T>
Извлекает типы параметров функции в виде кортежа.
function createUser(name: string, age: number, isAdmin: boolean) {
return { name, age, isAdmin }
}
type CreateUserParams = Parameters<typeof createUser>
// [name: string, age: number, isAdmin: boolean]
// Доступ к отдельному параметру по индексу
type FirstParam = Parameters<typeof createUser>[0]
// string
// Практический сценарий: обёртка над функцией
function withLogging<T extends (...args: any[]) => any>(
fn: T,
...args: Parameters<T>
): ReturnType<T> {
console.log('Вызов с аргументами:', args)
return fn(...args)
}
withLogging(createUser, 'Алиса', 30, false)
// Работает с перегрузками — берёт последнюю сигнатуру
declare function overloaded(x: string): string
declare function overloaded(x: number): number
type OverloadedParams = Parameters<typeof overloaded>
// [x: number] — последняя перегрузка
type Parameters<T extends (...args: any) => any> =
T extends (...args: infer P) => any ? P : never
infer P захватывает кортеж параметров функции. Ограничение T extends (…args: any) => any гарантирует, что T — функция.
ConstructorParameters<T>
Извлекает типы параметров конструктора класса.
class HttpClient {
constructor(
public baseUrl: string,
public timeout: number = 5000
) {}
}
type ClientParams = ConstructorParameters<typeof HttpClient>
// [baseUrl: string, timeout?: number]
// Фабричная функция на основе класса
function createInstance<T extends abstract new (...args: any) => any>(
Constructor: T,
...args: ConstructorParameters<T>
): InstanceType<T> {
return new (Constructor as any)(...args)
}
const client = createInstance(HttpClient, 'https://api.example.com', 3000)
// тип: HttpClient
// Работает с встроенными конструкторами
type DateParams = ConstructorParameters<typeof Date>
type ErrorParams = ConstructorParameters<typeof Error>
type RegExpParams = ConstructorParameters<typeof RegExp>
type ConstructorParameters<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: infer P) => any ? P : never
Аналогичен Parameters, но работает с конструкторными сигнатурами (new (…args) => …).
ReturnType<T>
Извлекает тип возвращаемого значения функции.
function fetchUser(id: number) {
return {
id,
name: 'Алиса',
roles: ['admin'] as const
}
}
type UserResult = ReturnType<typeof fetchUser>
// { id: number; name: string; roles: readonly ['admin'] }
// Полезно для типизации на основе существующих функций
type ApiResponse<T extends (...args: any) => any> = {
data: ReturnType<T>
status: number
timestamp: Date
}
type UserResponse = ApiResponse<typeof fetchUser>
// С асинхронными функциями — возвращает Promise<...>
async function loadData() {
return { items: [1, 2, 3], total: 3 }
}
type LoadDataReturn = ReturnType<typeof loadData>
// Promise<{ items: number[]; total: number }>
// Для получения «внутреннего» типа используйте Awaited
type LoadDataResult = Awaited<ReturnType<typeof loadData>>
// { items: number[]; total: number }
type ReturnType<T extends (...args: any) => any> =
T extends (...args: any) => infer R ? R : any
infer R захватывает тип, стоящий после => в сигнатуре функции.
InstanceType<T>
Извлекает тип экземпляра из конструкторной функции (класса).
class Logger {
private logs: string[] = []
log(message: string) {
this.logs.push(`[${new Date().toISOString()}] ${message}`)
}
getLogs(): string[] {
return [...this.logs]
}
}
type LoggerInstance = InstanceType<typeof Logger>
// Logger
// Зачем это нужно? Когда класс передаётся как аргумент
function createService<T extends new (...args: any[]) => any>(
ServiceClass: T
): InstanceType<T> {
return new ServiceClass()
}
const logger = createService(Logger)
// тип: Logger — автоматически выведен через InstanceType
logger.log('Сервис создан')
// Полезно с абстрактными классами
abstract class BaseRepository<T> {
abstract findById(id: number): T | null
abstract save(entity: T): void
}
// InstanceType работает и с абстрактными классами
type Repo = InstanceType<typeof BaseRepository>
// BaseRepository<unknown>
type InstanceType<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: any) => infer R ? R : any
infer R захватывает возвращаемый тип конструктора — это и есть тип экземпляра.
ThisParameterType<T>
Извлекает тип параметра this из функции. Если this не объявлен явно — возвращает unknown.
// Явный параметр this — первый "фиктивный" параметр
function toJSON(this: { name: string; age: number }): string {
return JSON.stringify({ name: this.name, age: this.age })
}
type ToJsonThis = ThisParameterType<typeof toJSON>
// { name: string; age: number }
// Если this не объявлен
function regular(x: number): number {
return x * 2
}
type RegularThis = ThisParameterType<typeof regular>
// unknown
type ThisParameterType<T> =
T extends (this: infer U, ...args: never) => any ? U : unknown
infer U извлекает тип из позиции this в сигнатуре.
OmitThisParameter<T>
Удаляет параметр this из типа функции. Результат — «чистая» сигнатура без контекста.
function greet(this: { name: string }, greeting: string): string {
return `${greeting}, ${this.name}!`
}
type GreetFn = typeof greet
// (this: { name: string }, greeting: string) => string
type CleanGreetFn = OmitThisParameter<typeof greet>
// (greeting: string) => string
// Практический сценарий: привязка контекста
const obj = { name: 'Мир' }
const boundGreet: CleanGreetFn = greet.bind(obj)
boundGreet('Привет') // 'Привет, Мир!'
type OmitThisParameter<T> =
unknown extends ThisParameterType<T>
? T
: T extends (...args: infer A) => infer R
? (...args: A) => R
: T
Если this не объявлен (unknown), функция возвращается как есть. Иначе — создаётся новая сигнатура без this.
ThisType<T>
Не трансформирует тип, а устанавливает контекст this для объектных литералов. Работает только с флагом --noImplicitThis.
// Типичный пример: описание объекта с методами
interface HelperMethods {
formatName(): string
formatAge(): string
}
interface Person {
name: string
age: number
}
// ThisType говорит TypeScript: внутри этих методов this = Person
const helpers: HelperMethods & ThisType<Person> = {
formatName() {
// this.name — OK, TypeScript знает, что this: Person
return this.name.toUpperCase()
},
formatAge() {
return `${this.age} лет`
}
}
// Используется в паттерне Vue Options API, Vuex и т.д.
// Более реалистичный пример: фабрика объектов
function defineComponent<D, M>(options: {
data: () => D
methods: M & ThisType<D & M> // this = data + methods
}) {
// реализация
}
defineComponent({
data() {
return { count: 0, message: 'Привет' }
},
methods: {
increment() {
// this.count — OK (из data)
this.count++
// this.reset() — OK (из methods)
},
reset() {
this.count = 0
this.message = 'Сброс'
}
}
})
ThisType<T> — это пустой интерфейс-маркер. Компилятор TypeScript обрабатывает его особым образом: он не добавляет никаких свойств, а лишь сообщает, каким будет тип this внутри объектного литерала.