Typescript + React Typing 총 정리

With·2021년 9월 11일
3

Hooks

useRef

// ref가 된 DOM의 type을 generic에 부여한다.
const inputEl = useRef<HTMLInputElment>(null)
// 추론된 타입 👉 React.RefObject<HTMLInputElement>

// 추가적으로 inputEl의 초기값이 null 이기때문에, input의 타입은 아래와 같다.
const input = inputEl.current; 
// 추론된 타입 👉 HTMLInputElement | null

// 이 경우 타입의 확실성을 부여 해주기 위해
// if 문안에서 작업을 해주거나, 또는 type assertion (! as ~) 을 해준다. 

// if 문 처리 (null 방지)
if(input) {
  input.focus()
}

// [ ] 가 초기값인 경우 never로 추론되므로, generic을 통한 명시가 필요하다.
const numbers = useRef<number[]>([]);

// type assertion
const input = inputEl.current as HTMLInputElement;
// 추론된 타입 👉 HTMLInputElement

useRef : 값을 바꾸어도 화면이 re-render가 되지 않는다.

useRef의 Type Overloading

useRef current의 readOnly 이슈
타입스크립트에서 useRef에 대해 3가지 로 타입선언을 해둠 (overloading 이라고 함)

useRef의 initialValue가 null 또는 undefined 일 때 아래의 케이스로 타입이 추론됨

const el_1 = React.useRef<number>(null);
// 추론된 타입 👉 React.RefObject<number>
// RefObject 로 타입이 추론된 경우 current가 readOnly 이므로 수정이 불가하다.
// el_1.current = 1 ❌
// 따라서 initial Value가 null 이고, ref의 current를 수정하는 코드가 필요하다면
// el_2와 같이 generic을 (useRef<T | null>) 선언해줘야 한다.
// T는 사용할 타입을 의미함

const el_2 = React.useRef<number | null>(null);
// 추론된 타입 👉 React.MutableRefObject<number | null>

const el_3 = React.useRef();
// 추론된 타입 👉 React.MutableRefObject<undefined>
// initialValue가 undefined 임에 따라 el_3.current에 들어갈 수 있는 값도 undefined만 가능하다.

useCallback

// ✨ handler를 useCallback으로 wrapping 하면 'e'가 type을 잃는다. 따라서 아래 방법으로 
// typing을 해줘야 한다.

// 방법 1 : event object에 직접 typing
const onChangeHandler = useCallback((e: React.FormEvent)=>{}, [])

// 방법 2 : useCallback의 generic 으로 typing
const onChangeHandler = useCallback<(e: React.FormEvent) => void>((e)=>{}, [])

// generic의 단점 : 가독성이 낮아진다.

useState

// 타입을 generic에 부여한다.
// type 추론이 되기 때문에 언넣어도 상관은 없다. 
const [state, useState] = useState<string>("")
const [number, setNumber] = useState<number>(0)


// useState에서 [] 을 initial로 사용하는 경우 never로 추론됨
// 따라서, typing이 필요함. type으로 선언하고, useState의 generic에 삽입

type IAry = {
  try: string,
  result: string, 
}
  
const [ary, setAry] = useState<IAry[]>([]);
// 추론된 타입 👉 const ary: IAry[]

useEffect, useMemo

특별히 typing 할 것이 없다..

Props


// type alias 또는 interface 를 선언 또는 import 해옴
import {TryInfo} from './NumberBaseball'

// 방법 1 : 리액트에서는 보통은 이렇게 안쓴다고 한다
const Try = ({tryInfo} : {tryInfo: TryInfo}) => {
  // 중략..
}

// 방법 2 : 이걸 더 많이 써요
const Try: React.FunctionCoponent<TryInfo> ({ TryInfo }) => {
  // 중략
}
// 또는 React.FC로 사용도 가능
// React.SFC 는 쓰지 않음

etc...

setTimeout( ), setInterval( )

  • 타입스크립트가 현재 본인을 실행중인 환경을 node.js 인지 browser 인지 구분 못하는 경우가 있다.
setTimeout(()=>{}, 1000)
// 추론된 타입 👇

function setTimeout<[]>(callback: () => void, ms?: number | undefined): NodeJS.Timeout (+2 overloads)
namespace setTimeout
// 타입이 NodeJS.Timeout 으로 추론된 상태

그래서 setTimeout()을 사용할 때는 window.setTimeout() 처럼 window를 명시적으로 사용해준다.

Tip

  • useRef와 useState 어떤 것을 쓰나?
    useRef는 값이 변경되어도 re-render가 안되기 때문에 View와 관련된 것이 아니라면 useRef를 쓰고, 화면의 상태와 관련된 것이라면 useState를 쓴다.

  • as const
    값을 고정할 때 사용한다.

const scores = { 
  r : 1,
  s : 0, 
  p : -1
}
// 이 경우 scores의 타입은 {r: number, s: number, p: number}로 추론된다. 
// 하지만 이것은 number 타입이 아니라 상수, 즉 1, 0, -1에서 변하지 않을 값들이기 때문에

const scores = {
  // ... 위와 동
} as const 

// 와 같이 as const 를 명시해주면, { readonly r: 1; readonly s: 0; readonly p: -1; } 로 타입이 변경된다. 
  • typeof 와 keyof

  • Object.keys 의 한계
    Object.keys(myObj)의 return type은 오직 string[] 이다. 따라서 아래와 같은 케이스에서는 type이 불분명해질 수 있다.

const scores = { 
  r : 1,
  s : 0, 
  p : -1
} as const 
// 추론된 타입 👉 {r: 1, s: 0, p: -1}

Object.keys(scores)
// 추론된 타입 👉 string[]

// 따라서 더 명확한 타입선언을 위해 type assertion을 해준다.
Object.keys(scores)  as ['r', 's', 'p']
// 추론된 타입 👉 ["r", "s", "p"]
// 동적으로 assertion 하기위해 typeof 나 keyof를 사용해도 좋다.
  • 고차함수의 타이핑
const onClickbtn = (params: Type) => 
(event: React.MouseEvent<HTMLButtonElement>) => {
// 
}
profile
주니어 프론트엔드 개발자 입니다.

0개의 댓글