← Назад к вопросам

Как можно задать опциональный Generic?

1.7 Middle🔥 221 комментариев
#TypeScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Опциональные Generic типы в TypeScript

Generic типы позволяют создавать переиспользуемые компоненты и функции, которые работают с различными типами данных. Иногда нужно, чтобы Generic был опциональным с дефолтным значением.

Способ 1: Generic с дефолтным значением

TypeScript позволяет задать дефолтный тип для Generic:

function processData<T = unknown>(data: T): T {
  return data
}

const result1 = processData(123)
const result2 = processData<string>('hello')

Способ 2: Multiple Generics с дефолтными значениями

Можно задать дефолтные значения для нескольких Generic типов:

interface Repository<K = unknown, V = unknown> {
  get(key: K): V | undefined
  set(key: K, value: V): void
}

class UserRepository implements Repository {
  private data = new Map()
  
  get(key: unknown): unknown {
    return this.data.get(key)
  }
  
  set(key: unknown, value: unknown): void {
    this.data.set(key, value)
  }
}

class TypedRepository implements Repository<string, number> {
  private data = new Map<string, number>()
  
  get(key: string): number | undefined {
    return this.data.get(key)
  }
  
  set(key: string, value: number): void {
    this.data.set(key, value)
  }
}

Способ 3: Generic для компонентов React

React компоненты часто используют Generic для типизации props:

import { ReactNode } from 'react'

interface CardProps<T = string> {
  title: T
  content: ReactNode
}

export function Card<T = string>({ title, content }: CardProps<T>) {
  return (
    <div className="card">
      <h2>{title}</h2>
      <p>{content}</p>
    </div>
  )
}

<Card title="Hello" content="World" />

interface ProductTitle {
  name: string
  price: number
}

<Card<ProductTitle> 
  title={{ name: 'Laptop', price: 999 }} 
  content="High-performance device" 
/>

Способ 4: Conditional Generics

Можно задать Generic в зависимости от другого Generic:

type ArrayElement<T> = T extends (infer U)[] ? U : T

type StringElement = ArrayElement<string[]>
type NumberElement = ArrayElement<number>

function getFirst<T extends any[]>(arr: T): ArrayElement<T> {
  return arr[0]
}

const first1 = getFirst([1, 2, 3])
const first2 = getFirst(['a', 'b'])

Способ 5: Generic с ограничениями (Constraints)

Можно ограничить Generic только определённые типы:

interface HasId {
  id: string
}

function getId<T extends HasId = { id: string }>(obj: T): string {
  return obj.id
}

getId({ id: '123', name: 'John' })
getId(123)  // ERROR

Способ 6: Generic для функций с Optional параметрами

function request<T = null>(url: string, data?: T): Promise<T> {
  return fetch(url, {
    method: 'POST',
    body: data ? JSON.stringify(data) : undefined
  })
    .then(res => res.json() as Promise<T>)
}

request('/api/users')

interface User {
  id: string
  name: string
}

request<User>('/api/user', { id: '1', name: 'John' })

Способ 7: Опциональные Generic в Utility Types

type Nullable<T = unknown> = T | null

const value1: Nullable = null
const value2: Nullable<string> = null
const value3: Nullable<string> = 'hello'

type Response<T = any> = {
  data: T
  status: number
  message: string
}

const res1: Response = { data: null, status: 200, message: 'OK' }
const res2: Response<{ id: string }> = { data: { id: '1' }, status: 200, message: 'OK' }

Способ 8: Правильное использование дефолтных Generics

function process<T, U = T>(item: T, processor: (item: T) => U): U {
  return processor(item)
}

const result = process(123, (num) => num * 2)

Ключевые моменты

  • Дефолтные значения — используй Generic = Type для дефолта
  • Multiple Generics — каждый может иметь свой дефолт
  • Conditional типы — используй extends для зависимостей между Generics
  • Constraints — ограничивай Generic только нужными типами
  • Порядок — Generic с дефолтом должен идти после Generic без дефолта
  • React компоненты — часто используют Generic с дефолтами

Опциональные Generics делают TypeScript код более гибким и переиспользуемым.