자바스크립트의 배열은 매우 유연하고 내부에 모든 타입의 값을 혼합해서 저장할 수 있습니다. 그러나 배열 안에 다른 타입의 값을 혼합해서 사용하거나, 다른 타입의 값을 추가하게 되면 배열을 읽을 때 혼란을 줄 수 있으며, 오류가 발생할 수도 있습니다. 그렇기 때문에 대부분의 배열은 하나의 특정 타입의 값만 가지고 있는 것을 볼 수 있습니다.
타입스크립트는 초기 배열 내부의 값에 대한 타입을 기억하고, 배열이 해당 데이터 타입에서만 작동하도록 제한하여 배열의 데이터 타입을 하나로 유지시킵니다.
위 코드를 보면 타입스크립트가 초기 배열 names
에 담긴 요소를 통해서 배열의 타입을 유추하는 것을 볼 수 있습니다.
배열 타입
- 배열의 요소 타입 다음에 [ ]을 배치 :
let names: string[];
- Array<타입> :
let names: Array<string>;
1️⃣ 배열과 함수 타입
배열 타입은 함수 타입에 무엇이 있는지 구별하기 위해서 괄호를 사용하여 구문 컨테이너를 만들어야 합니다. (괄호는 에노테이션의 어느 부분이 함수 반환 부분이고 어느 부분이 배열 타입 묶음인지를 나타내는 역할)
// number 배열을 반환하는 함수
let createNumbers: () => number[];
// number를 반환하는 함수를 요소로 갖는 배열
let numberCreators: (() => number)[];
2️⃣ 유니언 타입 배열
배열의 각 요소가 여러 타입 중 하나일 수 있음을 나타내려면 유니언 타입을 사용해야 합니다. 유니언 타입으로 배열 타입을 사용할 때 에노테이션의 어느 부분이 배열의 콘텐츠이고, 어느 부분이 유니언 타입 묶음인지를 명확하게 나타내야 합니다.(괄호를 사용해서 구분)
// number 타입 또는 string을 요소로 갖는 배열 타입
let numberOrArrayOfStrings: number | string[];
// number 또는 string을 요소로 갖는 배열 타입
let arrayOfNumberOrStrings: (number | string)[];
유니언 타입 배열에서 괄호 사용은 매우 중요한 역할을 합니다.
타입스크립트는 배열의 선언에서 두 가지 이상의 요소 타입이 포함되는 경우 유니언 타입의 배열이라고 유추합니다. (배열의 요소 타입은 배열에 담긴 요소에 대한 모든 가능한 타입의 집합)
3️⃣ 다차원 배열
2차원 배열 또는 배열의 배열은 두 개의 대괄호([ ])를 갖습니다.
2차원 배열은 배열을 요소로 갖는 배열이라고 볼 수 있기 때문에 아래와 같이 나타낼 수도 있습니다.
let arrayOfArraysOfNumbers: (number[])[];
만약에 타입스크립트가 빈 배열로 선언된 변수를 보게 된다면 어떤 타입으로 유추하게 될까요?
- 타입스크립트는 배열을
any[]
로 취급하고 모든 타입의 값을 받을 수 있도록 합니다. 모든 타입의 값을 받도록 내버려 둔다는 것은 안전성이 떨어지기 때문에 사용하지 않는 것이 좋습니다.
배열의 요소
타입스크립트는 배열의 요소를 찾아서 해당 배열의 타입을 되돌려줍니다. 유니언 타입으로 된 배열의 요소도 그 자체로 동일하게 유니언 타입을 갖습니다.
1️⃣ 불안정한 요소
타입스크립트의 타입 시스템은 불안정한 부분도 있습니다. 대부분 올바른 타입을 얻을 수 있지만, 때로는 값 타입에 대한 타입 유추가 올바르지 않을 수 있습니다. 특히 배열에서 이러한 모습이 나타납니다.
기본적으로 타입스크립트는 모든 배열의 요소에 대한 접근이 해당 배열의 요소를 반환한다고 가정하지만, 자바스크립트에서는 배열의 길이보다 큰 인덱스로 배열의 요소에 접근하면 undefined
를 반환합니다.
우리는 withString
함수의 반환 값을 보게 되면 ‘Cannot read property ‘length’ of undefined' 라는 타입 오류가 발생할 것이라고 생각할 수 있지만, 타입스크립트는 검색된 배열의 요소가 존재하는지 의도적으로 확인하지 않습니다.
스프레드와 나머지 매개변수
나머지 매개변수와 배열 스프레드는 자바스크립트에서 배열과 상호작용하는 핵심 방법입니다.
1️⃣ 스프레드
자바스크립트에서 … 스프레드 연산자를 사용하면 두 배열을 결합할 수 있습니다. 타입스크립트는 결합된 배열의 타입이 무엇인지 유추하는데, 만약 입력된 배열이 동일한 타입이라면 결합된 배열도 동일한 타입이 됩니다. 만약 서로 다른 타입의 두 배열을 결합하게 되는 경우 두 배열의 타입의 유니언 타입이 됩니다.
2️⃣ 나머지 매개변수 스프레드
나머지 매개변수를 위한 인수로 사용되는 배열은 나머지 매개변수와 동일한 타입을 가져야 합니다.
튜플
자바스크립트 배열은 이론상 어떤 크기라도 될 수 있습니다. 하지만 때로는 튜플(Tuple)이라고 하는 고정된 크기의 배열을 사용하는 것이 유용한 경우가 있습니다.
튜플 배열은 각 인덱스에 특정 타입을 갖는 요소의 배열을 말합니다. 튜플 타입을 선언하는 구문은 배열 리터럴처럼 보이지만 요소의 값 대신 타입을 적습니다.
- 튜플 배열은 배열의 모든 가능한 요소를 갖는 유니언 타입보다 더 구체적입니다.
자바스크립트에서는 단일 조건을 기반으로 두 개의 변수에 초기값을 설정하는 것처럼 한 번에 여러 값을 할당하기 위해서는 튜플과 배열 구조 분해 할당을 함께 사용합니다.
다음 코드에서 우리는 stringAndNumber
내부에 [string, number]
가 있는 것을 볼 수 있지만, 타입스크립트는 튜플 타입보다는 더 일반적인 (string | number)[]
타입으로 유추합니다.
const stringAndNumber = ['string', 123];
// stringAndNumber: (string | number)[]
const pairTupleLoose: [string, number] = stringAndNumber; // 오류
// Type '(string | number)[]' is not assignable to type '[string, number]'.
// Target requires 2 element(s) but source may have fewer.
만약 stringAndNumber
가 [string, number]
자체로 선언되었다면, pairTupleLoose
에 대한 값이 할당 되어 오류가 발생하지 않았을 것입니다.
그리고 타입스크립트는 튜플 타입의 튜플이 얼마나 많은 요소가 있는지 알고 있기 때문에 배열의 길이가 다른 튜플은 서로 할당할 수 없습니다.
1️⃣ 나머지 매개변수로서의 튜플
튜플은 구체적인 길이와 요소 타입 정보를 가지는 배열임을 알 수 있었습니다. 이러한 튜플의 특징은 함수에 전달할 인수를 저장하는데 유용합니다. 타입스크립트는 ...
나머지 매개변수로 전달된 튜플에 정확한 타입 검사를 제공할 수 있습니다.
아래의 코드에서 stringAndNumberPair
함수의 매개변수는 string
과 number
타입 입니다. 하지만 함수의 매개변수로 (string | number)[]
타입의 값을 인수로 전달하려고 하면 둘 다 동일한 타입이거나 타입의 잘못된 순서로 인해 내용이 일치하지 않을 가능성이 있습니다.(타입의 안정성을 보장할 수 없음)
pairTupleCorrect
와 같이 값이 [string, number]
튜플이라고 선언한다면, 타입스크립트가 값이 일치한다는 것을 유추할 수 있어 타입 오류가 발생하지 않습니다.
나머지 매개변수 튜플을 사용하고 싶다면 여러 번 함수를 호출하는 인수 목록을 배열에 저장해 함께 사용할 수 있습니다.
2️⃣ 튜플 추론
타입스크립트는 생성되는 배열에 대한 타입을 튜플 타입이 아닌 길이가 정해져 있지 않은 배열(가변 길이의 배열)로 취급하여 유니언 타입 배열로 유추합니다.
→ 배열이 변수의 초기값 또는 함수에 대한 반환값으로 사용되는 경우, 고정된 크기의 튜플이 아니라 유연한 크기의 배열로 가정
stringAndSize
함수의 반환값의 타입은 [string, number]
가 아니라 (string | number)[]
를 반환하는 것을 볼 수 있습니다.
3️⃣ 명시적 튜플 타입
함수에 대한 반환 타입 에노테이션처럼 튜플 타입도 타입 에노테이션에 사용할 수 있습니다. 함수가 튜플 타입을 반환한다고 선언되고, 배열 리터럴을 반환한다면 해당 배열 리터럴은 일반적인 가변 길이의 배열 대신 튜플로 간주됩니다.
stringAndSize
함수는 string
과 number
인 튜플을 반환한다고 명백하게 명시되어 있습니다.
4️⃣ const 어서션
명시적 타입 에노테이션에 튜플 타입을 입력하는 작업은 코드 변경에 따라 계속해서 작성 및 수정이 필요한 구문을 추가해야한다는 단점을 가지고 있습니다. 이때 const 어서션을 사용합니다.
- const 어서션인 as const 연산자는 값 뒤에 넣어서 사용
const unionArray = [123, 'Kim'];
// unionArray: (string | number)[]
const readonlyTuple = [123, 'Kim'] as const;
// readonlyTuple: readonly [123, "Kim"]
const 어서션은 유연한 크기의 배열을 고정된 크기의 튜플로 전환하는 것을 넘어서, 해당 튜플이 읽기 전용(read-only)이고 값이 수정 될 수 없음을 나타냅니다.
unionArray
는 전형적인 명시적 튜플 타입이므로 값을 수정할 수 있습니다. 하지만 as const
는 값이 변경될 수 있는 readonlyTuple
에 할당할 수 없도록 하고, 상수 pairConst
의 요소의 값을 수정을 허용하지 않습니다.
실제로 읽기 전용 튜플은 함수 반환에 편리합니다. 튜플을 반환하는 함수로부터 반환된 값은 보통 즉시 구조화되지 않으므로 읽기 전용인 튜플은 함수를 사용하는데 방해가 되지 않습니다.
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=307683870
러닝 타입스크립트
자바스크립트 세계를 정복한 타입스크립트는 강력한 타입 안정성에 힘입어 가장 빠르게 성장하고 있다. 언어의 역사를 살펴보며 진화 과정과 작동 방식을 이해하고, 개념 설명을 돕는 수많은
www.aladin.co.kr
'Books > Learning TypeScript' 카테고리의 다른 글
6. 인터페이스 (0) | 2023.03.04 |
---|---|
4. 함수 (0) | 2023.02.21 |
3. 객체 (0) | 2023.02.18 |
2. 유니언과 리터럴 (0) | 2023.02.16 |
1. 타입 시스템 (0) | 2023.02.15 |