const submitHandler = (event:React.FormEvent) => {
const submitHandler = (event:React.MouseEvent) => {
우리는 그동안 사용자 입력을 state, value 또는 ref를 통하여 관리하였다.
하지만 JS처럼 하면 안된다. 왜냐면 그동안은 타입 표기의 개념이 없었기 때문이다.
따라서 타입스크립트로 작업할 때는 우리가 만든 레퍼런스에 대해 더 많은 정보를 알려줘야 한다.
useRef로 레퍼런스를 만들 때 타입스크립트는 이 레퍼런스가 어떠한 요소에 연결될 거라는 사실을 알지 못하기 때문이다.
또 해당요소의 ref에 레퍼런스를 주더라도 명확하게 이 HTML 요소에 맞는 레퍼런스가 아니게 되기 때문에 button 요소의 ref에도 넣을 수있고 무튼 애매하게 되버린다. 그래서 이 레퍼런스에 저장될 데이터가 어떤 타입인지 명확히 밝혀야한다.
그래서 여기서 또 우리는 generic type을 사용한다.
const 사용자Ref = useRef<HTML엘리먼트>(null);
const submitHandler = (event:React.FormEvent) => {
event.preventDefault();
const enteredText = todoTextInputRef.current?.value; // <= 이부분
}
return (
<form onSubmit={submitHandler}>
<label htmlFor={"text"}>Todo text</label>
<input type={"text"} id={"text"} ref={todoTextInputRef}/>
<button>Add Todo</button>
</form>
);
여기서 우리가 물음표를 추가한 이유는 input값을 사용하려는 시점에 레퍼런스에 아직 값이 설정되지 않았을 수도 있기 때문이다.
물론 우리는 submitHandler가 호출되는 시점에 todoTextInputRef가 요소와 연결된다는 걸 알지만 TS는 알 길이 없다.
그래서 추가된 물음표가 타입스크립트에게 일단 값에 접근해보고 접근이 가능하다면, 그때 입력된 값을 가져와 enteredText 저장하라고 지시하는 것이다.
만약 접근이 불가능하면 아직 연결되지 않은 상태일 거고 null이 enteredText에 저장된다.
그래서 enteredText의 추론된 타입이 string 또는 undefined로 나타나는 것이다.
이는 타입스크립트가 실제 value를 가져올 수 있는지 반드시 알아야 할 필요는 없다는 뜻이다
하지만 우리는 이 시점에는 값이 null이 아니라는 것을 알기 때문에 즉, 레퍼런스와 요소가 연결되었다는 걸 알기 때문에 물음표 대신 느낌표를 사용할 수 있다
이 특수 기호는 타입스크립트에게 이 시점에는 절대 null이 아니라고 알려주는 것이다.
따라서 null이 아니라는 걸 100% 확신하는 경우에만 사용해야 한다.
이렇게 하면 추론된 타입에 string만 나온다.
null일 수도 있는 값을 다룰 때는
?
를 사용해서 먼저 해당 값에 접근해보고 null일 경우, 상수 또는 값을 저장할 변수에 null을 저장하고
!
를 사용하면 이 위치에서는 해당 값이 절대 null이 될 수 없으니 바로 객체의 프로퍼티로 들어가서 null이 아닌 실제 값을 가져오라는 뜻이다.
만약 우리가 자식=>부모로 데이터를 넘길 때 보통 on000라고 하여 부모=>자식 컴포넌트로 보낸다음 자식 컴포넌트에서 로직을 거쳐 나올 결과값을 props.on000( )로 하여 메서드에 담에 올렸다. 이때 이것을 TS로 구현을 하려면 props에서 넘어온 props.on000( )를 데이터 타입으로 지정해주어야한다.
바로 이를 ‘함수 타입’이라 불리는 타입으로 지정해야 한다.
const NewTodo: React.FC<{ onAddTodo: (text: string) => void }> = (props) => {
단순히 화살표 함수를 사용하면 된다.
화살표 다음에는 이 함수의 반환 타입(리턴 타입)을 정의하면 되는데
여기의 onAddTodo는 값을 반환할 필요가 없다.
그 이유는 props객체의 속성중 하나인 매서드가 실행되었는데 그 메서드가 반환값이 없다면 void로 하는 것이 맞다.
코드를 보면 더 이해가 쉬운데
const submitHandler = (event: React.FormEvent) => {
event.preventDefault();
const enteredText = todoTextInputRef.current!.value;
if (enteredText.trim().length === 0) {
// throw an error
return;
}
props.onAddTodo(enteredText); // <= 이 부분
};
위의 NewTodo 컴포넌트 함수의 일부이다. props.프롭함수(매개변수) 이 부분을 그냥 데이터 타입으로 변환한 후 위의 함수타입안에 각각 넣어주면 된다.
그리고 당연히 부모 컴포넌트에서는 "프롭함수" 와 완전 동일한 데이터 타입의 위치와 조건으로 선언이 되어있어야 한다.
즉, 부모컴포넌트의 프롭함수 정의의 데이터 타입
=== 부모 컴포넌트 => 자식컴포넌트의 속성
=== 자식 컴포넌트의 함수타입
요 3개가 3위일체가 되어야 한다.
const [state변수, setstate변수] = useState<데이터타입>(init데이터);
<>
을 추가하여 데이터타입을 지정할 수 있다.const [todos, setTodos] = useState<Todo[]>([]); // 1.
const addTodoHandler = (todoText: string) => { // 2.
const newTodo = new Todo(todoText); // 3.
setTodos((prevState)=>{ // 4.
return prevState.concat(newTodo); // 5.
})
};