FormEvent
는 입력 요소의 상태를 직접 관리하지 않으면서 입력 요소의 값을 얻는 편리한 방법이지만, 처음 TS를 React와 함께 사용할 때 폼 이벤트의 타입을 어떻게 확장할 것인가 고민했다.
타이핑이 안되어 있는 경우
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { FormEvent } from 'react' | |
const App: React.FC = () => { | |
const [flag, setFlag] = useState<boolean>() | |
const onSubmit = async (event: FormEvent) => { | |
event.preventDefault() | |
// @ts-ignore | |
const { value } = event.target.mailid // mailid is 'any' type | |
setFlag(await submitID(value)) | |
} | |
return ( | |
// ... | |
) | |
} |
제너릭으로 flag
라는 상태의 타입을 명시하는 것처럼, 폼 요소로 감싸진 입력 요소의 타입을 정의하는 법을 알고 싶었다.
타이핑 된 경우
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface FormElements extends HTMLFormElement { | |
mailid: HTMLInputElement | |
} | |
interface FormTarget extends FormEvent<HTMLFormElement> { | |
target: FormElements | |
} | |
const App: React.FC = () => { | |
const [flag, setFlag] = useState<boolean>() | |
const onSubmit = async (event: FormTarget) => { | |
event.preventDefault() | |
setFlag(await submitID(event.target.mailid.value)) | |
} | |
//... |
굳이 HTMLFormElement
를 두 번 써야 되나..? 라고 의문이 들지만 FormTarget.target
이 덮어 씌워지는 상황이다.
“그러면 FormEvent<HTMLFormElement>
는 필요 없지 않는가요?”
무척이나 엄격한 TS의 타입 규칙 때문에 FormEvent
는 HTMLFormElement
를 제너릭 타입으로 갖고 있어야 하고, 그 하위의 개체인 target
은 HTMLFormElement
를 상속받으면서 그 아래 입력 요소 타입을 가져야 되어야 하는 상황입니다. 아마 상호적으로 타입을 참조하면서 생기는 문제로 보입니다.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { FormEvent } from 'react' | |
export interface TypeForm extends FormEvent<HTMLFormElement> {} |
여러 컴포넌트에서 폼 요소를 사용한다면 위와 같이 FormEvent
를 정의해두자
이제 어떤 DOM 이벤트가 와도 @ts-ignore를 쓰지 맙시다!