기존의 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에 명시 적으로 전달해야합니다.
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.
왜 호환이 안되는지, 합칠 수 없는지 정확한 이유는 찾지 못했는데,
혹시 알고 게시다면 댓글 부탁드립니다. (_ _)