News/Frontend

[TypeScript, TkDodo의 블로그 번역] 타입스크립트의 배열 타입 선언, 현명하게 선택하기 (제너릭 VS 배열)

남남이루 2023. 8. 26. 12:46

Array Types in TypeScript (원문 바로가기)

23. 8. 19 발행 _ TkDodo’s blog


글을 시작하기 전에..

이 포스팅은 ReactQuery의 co-maintainer인 TkDodo의 블로그 글을 의역해 정리한 글이다. 해당 블로그는 ReactJs, TypeScript, 비동기에 대한 글이 주기적으로 올라오고 있다. Array 과 string[] 두 표기법의 공식 번역 용어를 찾을 수 없어 전자는 제너릭 노테이션(제너릭 표기법), 후자는 배열 노테이션(배열 표기법)이라 칭하겠다.

* TanStack/Query Github (https://github.com/TanStack/query))

제너릭 노테이션 Array<string> VS 배열 노테이션 string[]

두 노테이션 함수적 차이 X, 개인적 선호의 차이, 뭐로 하든 둘 중에 하나만 일관성 있게만 해라!

사람들은 배열 노테이션을 더 많이 쓰고 있다

그렇다면 둘 중 어떤 표기법을 선택하는 것이 좋을 지 얘기해보자.

  1. 짧은 것? :
    짧다는 것은 장점이 될 수 없다, let 을 const 코드보다 짧다고 아무 곳에나 let을 쓰진 않을 것이므로!
  2. 가독성? :
    우리는 왼쪽에서 오른 쪽으로 읽기 때문에, 더 중요한 것은 왼쪽에 위치한다. string[]은 string타입과 혼동되기 쉽다. 따라서 Array<string>이 좀 더 배열 속성을 한 눈에 보여줄 수 있다. 타입의 속성이 길어질 수록, [] 표시를 읽기가 힘들어진다.
// 배열 노테이션 예시, 속성이 길어지면 마지막의 대괄호를 읽기 어려워진다.
const options: {
  [key: string]: unknown
}[]
// Array를 표기하니 multiline에서 가독성이 좋아진다.
const options: Array<{
  [key: string]: unknown
}>
  1. 읽기 전용 배열 (Readonly) :
    우리가 받는 대부분의 입력값은 객체전이(Mutation)를 피하기 위해 읽기전용이어야 한다. 만약 제네릭 노테이션을 사용한다면, Array를 단순하게 ReadonlyArray로 바꿔버리면 된다! 만약 배열 노테이션(string[])을 사용했다면, readonly string[] 으로 작성할 수 밖에 없고, 이는 두 덩어리로 분리되어 보인다.
  2. 유니온 타입 :
    타입을 합성할 때 제너릭(Array<string>)은 타입을 추가하기만 하면 된다. 하지만 배열 노테이션에서는 이상해진다. 아래 예시는 배열 요소에 문자와 숫자 두 타입 받고자 할 때이다.
    items : Array<string | number>
    items: string | number[]  ➭ 원하는 대로 동작X. 뜻도 불분명해진다.

    (string | number)[]  : () 괄호를 같이 써야 같은 의미가 된다..

  3. keyof
    객체를 인자로 받는 함수가 있다고 하자, 우리는 이 함수에 객체의 키 배열도 인자로 보내고 싶다. 다만 두 번째 배열의 키 배열 인자는 객체에 존재하는 키들만 전달하도록 하고 싶다. 이때 keyof 타입 오퍼레이터를 사용한다.

제너릭 노테이션에서는 당연히 잘 되고, 배열 노테이션에서도 에러가 표시가 뜨지 않는다.

제너릭 표기 예시

 

배열 표기 예시, 선언에서는 에러가 나지 않는다

 

함수 실행시 에러를 반환한다


하지만 배열 표기법은 함수 선언할 때는 타입에러가 뜨지 않음에도 함수에 인자를 전달해 실행하려고 하면 에러메시지가 뜬다.


왜일까?? 슬프게도 아직도 왜 keyof TObject\[]가 안 되는지 모르겠다, 다만 이렇게 바꾸면 작동한다.
(keyof TObject)[]

작동은 하지만 이상한 문법...


이상한 문법이다.. 앞서 언급한 것들이 배열 노테이션으로 일할 때 생기는 모든 이슈들이다. 앞의 전략들이 eslint의 기본 설정인 것이 아쉽고, (아마도 이 점 때문에) 대부분의 사람들이 선호한다. 또한 IDE들과 TypeScrtipt Playground는 배열 노테이션으로 타입을 보여준다..

아마 이 아티클이 제너릭 노테이션이 더 낫다는 것을 커뮤니티에 설득하는 데 도움을 줄 수 있을 것이다.



이번 아티클을 읽고, 리팩토링 소재로 삼으면 좋겠다는 생각을 했다. 전체 서비스에 심각한 오류를 발생시키지 않지만 앞으로의 타입안정성에 도움이 되기 때문이다. 특히 가독성 항목에서 속성값이 길어질 때의 예시를 보고 휴먼에러를 발생시키기 쉽다는 생각이 들어 경각심이 생겼다. 좀 더 제너릭 표기법에 익숙해지는 훈련을 해야겠다고 느꼈다.