React에서 KeyboardEvent Type에서 e.target.value 사용시 에러 이슈

varcode·2022년 5월 14일
2

이슈기록

목록 보기
2/2
post-thumbnail

기존의 JS로 작성한 React 프로젝트에 TS를 적용하는 과정에서 생긴 Input태그 KeyboardEvent관련 이슈입니다.

function YourComponent() {
  const onAddItem = (e: KeyboardEvent<HTMLInputElement>) => {
    console.log(e.key);
    console.log(e.target.value);
  }
  return <Input onKeyDown={onAddItem} />
}

위와 같이 Input에 onKeyDown 이벤트를 추가하려는 상황에서
event에 KeyboardEvent<HTMLInputElement>로 타입을 지정하게 되면
e.target.value 부분에서 다음과 같은 에러가 뜹니다.
Property 'value' does not exist on type 'EventTarget'.ts(2339)
이런 에러메시지가 뜨는데 그 이유는,

사용하려는 KeyboardEvent도 DOM 요소나 window 객체에서 발생할 수 있으므로,
이론적으로는 event.target을 요소로 정의하는 것은 의미가 없습니다.
DOM 요소에 대한 이벤트라면 event.target을 안전하게 가정할 수 있습니다.
타겟이되는 HTMLElement의 타입을 TypeScript에 명시 적으로 전달해야합니다.

따라서 적절한 Element 유형으로 캐스팅해서 사용해야합니다.

ex) const target = e.target as HTMLElement

실제로 index.d.ts 파일을 보면 KeyboardEvent에 target 속성은 정의 되어있지 않는 것을 볼 수 있습니다.

// 1. Keyboard Events
onKeyDown?: KeyboardEventHandler<T> | undefined;

// 2. KeyboardEventHandler
type KeyboardEventHandler<T = Element> = EventHandler<KeyboardEvent<T>>;

// 3. KeyboardEvent
interface KeyboardEvent<T = Element> extends UIEvent<T, NativeKeyboardEvent> {
  altKey: boolean;
  /** @deprecated */
  charCode: number;
  ctrlKey: boolean;
  code: string;
  /**
           * See [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#keys-modifier). for a list of valid (case-sensitive) arguments to this method.
           */
  getModifierState(key: string): boolean;
  /**
           * See the [DOM Level 3 Events spec](https://www.w3.org/TR/uievents-key/#named-key-attribute-values). for possible values
           */
  key: string;
  /** @deprecated */
  keyCode: number;
  locale: string;
  location: number;
  metaKey: boolean;
  repeat: boolean;
  shiftKey: boolean;
  /** @deprecated */
  which: number;
}

추가로

type HTMLElementEvent<T = HTMLElement> = KeyboardEvent & {
  target: T;
};

이처럼 & 연산자를 이용해 여러 개의 타입 정의를 하나로 합치는 방식을 인터섹션 타입 정의 방식을 이용하는 방법도 있겠으나, 이 경우 onKeyDown에 에러가 발생합니다.

return <Input onKeyDown={onAddItem} /> // onKeyDown error
Type 'KeyboardEvent<HTMLInputElement>' is not assignable to type '{ target: HTMLInputElement; }'
Types of property 'target' are incompatible.

왜 호환이 안되는지, 합칠 수 없는지 정확한 이유는 찾지 못했는데,
혹시 알고 게시다면 댓글 부탁드립니다. (_ _)

profile
백엔드와 Rust가 취미인 프론트엔드 개발자

0개의 댓글