[TS] 리액트 이벤트, 제네릭 컴포넌트, HTMLAttributes

리액트 이벤트

  • 리액트는 가상 DOM을 다루면서 이벤트도 별도로 관리한다. onclick , onchange 같이 DOM 엘리먼트에 등록되는 이벤트 리스너와 달리, 리액트 컴포넌트(노드)에 등록되는 이벤트 리스너는 onClick , onChange 처럼 카멜 케이스로 표기한다.
  • 리액트 이벤트는 브라우저의 고유한 이벤트와 완전히 동일하게 동작하지 않는다. 리액트 이벤트 핸들러는 이벤트 버블링 단계에서 호출된다.
  • 리액트는 브라우저 이벤트를 합성한 합성 이벤트(SyntheticEvent)를 제공한다.
type EventHandler<Event extends React.SyntheticEvent> = (
  e: Event
) => void | null;
type ChangeEventHandler = EventHandler<ChangeEvent<HTMLSelectElement>>;

const eventHandler1: GlobalEventHandlers['onchange'] = (e) => {
  // Event.target: EventTarget | null
  console.log(e.target);
};

const eventHandler2: ChangeEventHandler = (e) => {
  // React.ChangeEvent<HTMLSelectElement>.target: EventTarget & HTMLSelectElement
  console.log(e.target);
};
  • 리액트의 SyntheticEvent을 사용하면 이벤트 핸들러의 타입을 지정할 수 있다.
const Select = () => {
  const handleChange: React.ChangeEventHandler<HTMLSelectElement> = (e) => {
    // TODO
  };

  return <select onChange={handleChange}></select>;
};

제네릭 컴포넌트

  • 함수 컴포넌트도 함수이므로 제네릭을 사용한 컴포넌트를 구현할 수 있다. 제네릭을 지정한 뒤 props를 넘겨주면 타입을 자동으로 추론해준다.
interface SelectProps<OptionType extends Record<string, string>> {
  options: OptionType;
  selectedOption?: keyof OptionType;
  onChange?: (selected?: keyof OptionType) => void;
}

const Select = <OptionType extends Record<string, string>>({
  options,
  selectedOption,
  onChange,
}: SelectProps<OptionType>) => {
  return <></>;
};

const fruits = {
  apple: '사과',
  banana: '바나나',
  blueberry: '블루베리',
};

const FruitSelect = () => {
    // selectedOption 타입을 자동으로 추론
  return <Select options={fruits} selectedOption="apple" />;
};

HTMLAttributes

  • className , id 와 같은 리액트 컴포넌트의 기본 props를 추가할 때 직접 추가해줘도 되지만 리액트에서 제공하는 타입을 사용하면 더 정확한 타입을 설정할 수 있다.
  • ComponentPropsWithoutRef는 리액트 컴포넌트에서 ref를 제외한 prop 타입을 반환해준다.
  • Pick 유틸리티 타입을 통해 ReactProps에서 여러 개의 속성 타입을 가져올 수 있다. 이를 통해 인터페이스를 확장해준다.
type ReactSelectProps = React.ComponentPropsWithoutRef<'select'>;

interface SelectProps<OptionType extends Record<string, string>>
  extends Pick<ReactSelectProps, 'id' | 'className'> {
  options: OptionType;
  selectedOption?: keyof OptionType;
  onChange?: (selected?: keyof OptionType) => void;
}

'TypeScript' 카테고리의 다른 글

[TS] DetailedHTMLProps, ComponentPropsWithoutRef  (0) 2025.02.11
[TS] Superstruct  (0) 2025.02.04
[TS] 컴파일러 구조  (0) 2025.02.01
[TS] 런타임과 컴파일  (0) 2025.01.31
[TS] Record 원시 타입 키 개선  (1) 2025.01.30