이 연습에서는 매우 일반적인 패턴을 살펴보겠습니다.

여기서는 ComponentProps 를 가져와서 Input 컴포넌트에서 사용하겠습니다.

import { ComponentProps } from "react";
import { Equal, Expect } from "../helpers/type-utils";

export const Input = (
  props: ComponentProps<"input"> & { onChange: (value: string) => void }
) => {
  return (
    <input
      {...props}
      onChange={(e) => {
        props.onChange(e.target.value);
      }}
    ></input>
  );
};

Input에는 기본적으로 React.ChangeEvent 를 포함한 전체 이벤트 객체와 함께 e.dafaultPrevented, eventPhase 등을 제공하는 onChange 가 있습니다.

종종 우리는 이 모든 것을 원하지 않습니다.

예를 들어 새 값을 전달하거나 일부 네이티브 엘리먼트만 변경하고 싶다고 가정해 보겠습니다.

Input은 다음과 같이 보일 수 있습니다.

export const Input = (
  props: ComponentProps<"input"> & { onChange: (value: string) => void }
) => {
  ...

컴포넌트 내부에서는 모든 것이 정상적으로 보이지만 막상 사용하려고 하면 예상대로 작동하지 않습니다.

부모 컴포넌트 아래에서 테스트에서 오류를 확인할 수 있습니다.

const Parent = () => {
  return (
    <Input
      onChange={(e) => {
        console.log(e);

        // error below!
        type test = Expect<Equal<typeof e, string>>;
      }}
    ></Input>
  );
};

e 는 단순한 문자열이 아니라는 것을 보여줍니다. 대신 문자열 또는 React.ChangeEvent<HTMLInputElement> 로 타입되어집니다.

뭔가 잘못되고 있습니다.

Input 컴포넌트의 현재 구현에서, onChange가 실제로 ComponentProps<”input”> 에서 props를 재정의 하거나 제거하지 않았습니다.

Challenge