나는 평소에 이벤트 핸들러 타입을 작성할 때에는 아래와 같이 작성했었는데, 이벤트 별 핸들러 타입 이름과 HTMLElement의 이름을 매번 떠올려야 하는 점이 은근히 귀찮았었다.
import React from 'react';
function Component() {
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
console.log(e.target.value);
};
return <input onChange={handleChange} />;
}
그러던 중 ComponentProps
를 통해 input의 onChange props 타입을 사용하는 방법을 알게 되었다.
별도의 타입 네이밍을 떠올려야할 필요없이 'input'의 'onChange' props를 찾는다는 점이 더 직관적으로 느껴진다.
import { ComponentProps } from 'react';
function Component() {
const handleChange: ComponentProps<'input'>['onChange'] = (e) => {
console.log(e.target.value);
};
return <input onChange={handleChange} />;
}
위 방식에서 한번 더 간소화하여 Event 라는 별도의 타입 alias를 만들어 보았다. ComponentProps 타입 사용 방식조차 생각할 필요 없이 바로 쓸 수 있어서 좋고, 읽기에도 더 직관적인 것 같다.
import { ComponentProps, DOMAttributes } from 'react';
type EventHandlers<T> = Omit<
DOMAttributes<T>,
'children' | 'dangerouslySetInnerHTML'
>;
export type Event<
TElement extends keyof JSX.IntrinsicElements,
TEventHandler extends keyof EventHandlers<TElement>
> = ComponentProps<TElement>[TEventHandler];
function Component() {
const handleChange: Event<'input', 'onChange'> = (e) => {
console.log(e.target.value);
};
return <input onChange={handleChange} />;
}
참고 링크: https://twitter.com/sebastienlorber/status/1512420374201446405?s=20&t=Ck28ovkX7Ms-ihShDa8HLA