230910.log

Universe·2023년 9월 10일
0

log

목록 보기
14/14
🗓️ 날짜 : 2023.09.10

📚 할 일 : 영어 레퍼런스 번역하면서 공부해보기

⌛ 공부시간 : 22:00 ~ 23:00

Array Types in TypeScript (2)

Union type

만약 아래의 add 함수에 추가사항을 구현할 때,
문자열과 숫자의 배열을 허용할 수 있도록 구현하면 어떻게 될까?
일반 표기법의 경우에는 문제가 없다.

// ✅ 이전과 동일하게 작동한다.
function add(items: Array<string | number>, newItem: string | number)

그러나 배열 표기법의 경우 이상해지기 시작한다.

// ❌ 괜찮아 보이지만 그렇지 않다.
function add(items: string | number[], newItem: string | number)

오류를 즉시 발견할 수 없다면 그 부분이 문제이다.
너무 숨겨져 있기 때문에 알아보는데 오랜 시간이 걸린다.
실제로 해당 함수를 구현하면 어떤 오류가 발생하는지 알아보자.

// ❌ 왜 동작하지 않지 ?
function add(items: string | number[], newItem: string | number) {
  return items.concat(newItem)
}

위의 함수는 아래와 같은 오류가 표시된다.

Type 'string' is not assignable to type 'ConcatArray<number> & string' (2769)

이 의미는 나에게 아무런 의미가 없다.
퍼즐을 해결하기 위해서 연산자의 우선순위에 대해서 살펴보자.
[] 연산자는 | 연산자 보다 강력하게 bind 되므로 지금 우리는 items 의 타입을
string | number[] 로 만들었다.

우리가 원하는 것은 (string | number)[] 를 넣어 코드가 작동하도록 하는 것이다.
일반 표기법은 문제가 발생하지 않는데, Array와 내용을 <> 로 분리하기 때문이다.

여전히 일반 표기법이 낫다는 생각이 들지 않는가 ?
마지막 예시가 있다. (last argument 라고 표현)

Key of

매우 일반적인 예시를 보자.
아래의 함수는 객체를 전달받는 함수가 있고 이 객체에 할당 가능한 키 배열을 같은 함수에 전달한다.
pick 이나 omit 과 같은 기능을 구현하기 위해서 필요하다.

const myObject = {
  foo: true,
  bar: 1,
  baz: 'hello world',
}

pick(myObject, ['foo', 'bar'])

두 번째 인자로 허용된 키만 전달할 수 있도록 하고 싶다면 어떻게 해야할까?
key of type operator 를 사용하면 된다.

function pick<TObject extends Record<string, unknown>>(
  object: TObject,
  keys: Array<keyof TObject>
)

물론, 위의 배열에 일반 표기법으로 작성할 때는 모든 것이 잘 작동한다.
하지만 배열 표기법을 사용했을 때는 어떻게 될까 ?

function pick<TObject extends Record<string, unknown>>(
  object: TObject,
  keys: keyof TObject[]
)

놀랍게도, 에러가 없고 괜찮을것이다.
에러가 없다는 것이 더 나쁜데, 왜냐하면 위의 함수에는 에러가 있지만
함수의 선언에서 에러로 표시되지 않고 호출하려고 하면 에러가 발생하기 때문이다.

pick(myObject, ['foo', 'bar'])

Argument of type 'string[]' is not assignable to parameter of type 'keyof TObject[]'.(2345)

뭣?
이 메시지는 이전의 메시지보다 더 말도 안된다.
실제 코드 베이스에서 이 오류가 처음 발생했을 때,
나는 5분동안 바라만 보고 있었다.
왜 나의 key 가 문자열이 아니라는 말인가!

이 오류를 개선하기 위해 나는 좌우를 바꿔보고 타입 엘리어스를 추출해보고 했지만
성공하지 못했다.
그러다 충격을 받았다. 괄호 안에 또 다른 문제가 있지 않을까 ?

그렇다. 슬픈일이다.
왜 내가 그런 것 까지 케어를 해야하지 ?
오늘에 이르러서도 나는 keyof TObject[]의 적절한 input 이 무엇인지 알지 못했다.
알아낼 수가 없었다.
난 단지, 올바른 입력방법이 (keyof TObject)[] 라는 것만 알게 되었다.

function pick<TObject extends Record<string, unknown>>(
  object: TObject,
  keys: (keyof TObject)[]
)

아무 것도 아닌 멍청한 구문에 감사를 표한다.

그래서,
내가 배열 표기법으로 작성할 때 겪은 문제들은 이것이라고 생각한다.
eslint rule 의 기본 설정 때문에 많은 사람들이 여전히
배열 표기법을 선호하고 있다는 것이 슬프다.

또한, 명확하게 다르게 정의되어 있음에도,
IDE와 TS Playground 에서도 배열 표기법으로 유형을 표시하는 것이 슬프다.

type ArrayOfObject = Array<typeof myObject>
// ^? type ArrayOfObject = { foo: boolean; bar: number; bax: string;}[]

어쩌면, 이 article이 커뮤니티에 일반 표기법이 배열 표기법보다 더 낫다는 것을
설득하는데 도움이 될 수도 있고, 이것이 기본설정이 되도록 집단적으로 움직이는 방법이
될지도 모른다.
그러면 어쩌면, 어쩌면 도구들도 뒤따를지도 모른다.

[2]

profile
Always, we are friend 🧡

0개의 댓글