나홀로 리액트 스터디 0.4

Jade·2023년 12월 13일
0

React

목록 보기
4/7
post-thumbnail

오늘은 리액트를 사용할 때 좋은 타입스크립트 개념들에 대한 내용들이 많다

🍐 불가피하게 타입을 아직 단정할 수 없는 경우 any대신 unknown 활용

unknown 활용 시 type narrowing을 해주어야 하는데, 이를 통해 타입의 범위를 의도했던 대로 좁힐 수 있게 된다.
(*unknown 과 반대되는 타입이 never인데, 어떠한 타입도 들어올 수 없는 경우에 사용한다.)


🍐 타입 가드 활용하기

조건문과 함께 타입 가드를 사용해 타입을 좁혀서 변수나 함수를 사용함
특정 요소의 자료형을 확인하는 typeof 외에도 지정한 인스턴스가 특정 클래스의 인스턴스인지 확인하는 instanceof,
어떤 객체에 해당 key가 존재하는지를 확인하는 in도 있다.


🍐 제네릭

제네릭을 잘만 활용하면 좋을 것 같다는 생각을 최근 작성된 어드민쪽 코드를 보면서 하고 있었다.
제네릭은 함수나 클래스 내에서 단일 타입이 아닌 다양한 타입에 대응할 수 있도록 도와주는데,
타입은 다르지만 비슷하게 다른 작업을 하는 컴포넌트들을 하나의 제네릭으로 선언해 간단하게 작성할 수 있게 된다.

//제네릭 활용하지 않은 경우
function getfirstAndLast(list:unknown[]){
  return [list[0],list[list.length-1]
          }
          
const [first, last] = getFirstAndLast([1,2,3,4])
  
first//unknown
last//unknown
//제네릭 활용 
function getFirstAndLast<T>(list:T[]):[T,T]{
  return [list[0],list[list.length-1]
          }

//이 경우 first, last 의 타입은 number
const [first,last] = getFirstAndLast([1,2,3,4])

 //이 경우 first, last의 타입은 string
const [first, last] = getFirstAndLast(['a','b','c'])

직접 작성하는 함수가 아닌 useState에도 제네릭으로 타입을 선언해줄 수 있는데, 종종 useState를 사용할 때 initialState를 넘기지 않은 상태로 사용하면 값을 undefined로 추론하는 문제가 생긴다.

복수의 제네릭을 사용할 수도 있는데, 이 경우에는 제네릭의 의미를 알 수 있는 네이밍을 하는 것이 좋다.

function multiple<First,Last>(a1:First,a2:Last):[First,Last]{
  return [a1,a2]
}

const [a,b] = multiple<string,boolean>('true',true)

🍐 인덱스 시그니처

객체의 키를 정의하는 방식을 인덱스 시그니처라고 한다
[key:string]:string과 같이 작성하는데 키의 범위를 지금과 같이 string으로 작성하면 범위가 너무 넓아지기 때문에 동적으로 선언되는 경우는 지양하고, 필요에 따라 좁혀서 사용해야 한다.

//객체의 키 좁히기 

//1.Record 사용 (객체의 key, value 지정함)
type Hell = Record<'fire'|'devil',string>
  
const hell : Hell = {
  fire: 'fire',
  devil: 'devil'
}

//2. 타입을 사용
type Hell = {[key in 'fire'|'devil']:string}

위와 같이 작성한 뒤 Object.keys를 이용해 키를 배열로 뽑아내고, 뽑아낸 배열을 순회하면서 hell이라는 객체의 value를 반환한다면 에러가 발생한다

//Element implicitly has an 'any' type 
//because expression of type 'string' can't be
//used to index type 'Hell'
//No index signature with a parameter of type
//'string' was found on type 'Hell'

Object.keysstring[]을 반환하는데 이 string은 hell의 인덱스 키로 접근할 수가 없다 (hell의 인덱스 시그니처는 'fire'|'devil'이니까)

이런 에러를 해결하는 방법은

//1.as - 타입 단언
Object.keys(hell) as Array<keyof Hell>).map((key) =>{
  const value = hell[key]
  return value 
  {

    
//2.타입 가드 함수 KeyOf만들기
//*Array.from은 순회 가능한, 유사 배열 객체에서 얕게 복사된 새로운 인스턴스를 생성하는데, 두번째 인자로 매 요소마다 호출할 함수를 받는다 (map 함수와 유사한 형태) 
function keyOf<T extends Object>(obj:T):Array<keyof T>{
  
  //가져온 배열에 대해서도 타입 단언 처리
  return Array.from(Obejct.keys(obj)) as Array<keyof T>
  }
  
//keyOf 사용하기
keyOf(hell).map((key) => {
  const value = hell[key]
  return value
})

//3. 가져온 키에 대해 타입 단언 처리하기 
Obejct.keys(hell).map((key) => {
  const value = hell[key as keyof Hell]
  return value
})

🦆 덕 타이핑 (구조적 타이핑)

타입스크립트의 핵심 원칙 중 하나로 타입 검사의 초점이 '값의 형태'에 맞춰져 있음을 뜻한다
오리처럼 걷고, 헤엄치고, 소리내면 그것이 무엇이든 오리라고 부를 수 있는 것처럼 어떤 객체가 필요한 변수와 매서드만 지닌다면 해당 타입에 속한다고 인정해준다

위 인덱스 시그니처 예시에서 Object.keys가 반환하는 값은 제네릭으로 정해진게 아니라 string[]으로 고정되어 있었다
이는 자바스크립트가 객체 타입에 열려있기 때문에 타입스크립트 역시 모든 키가 들어올 수 있는 가능성에 대응하기 위해 포괄적으로 지정해둔 것

profile
키보드로 그려내는 일

0개의 댓글