자바스크립트 배열은 매우 유연하며 내부에 모든 타입의 값을 혼합하여 저장가능하다
하지만, 대부분의 자바스크립트 배열은 하나의 특정 타입의 값만 가지며 다른 타입의 값을 추가할 시 배열을 읽을 때 프로그램 오류가 생길 수 있다.
타입스크립트는 초기 배열에 어떤 데이터 타입이 있는지 기억하며, 배열이 해당 데이터 타입에서만 작동하도록 제한하여 배열의 데이터 타입을 하나로 유지시킨다.
const elements = [true, null, undefined, 42];
elements.push(”even”, [”more”]);
// 배열의 값 : [true, null, undefined, 42, “even”, [”more”]]
6.1 배열 타입
다른 변수선언과 마찬가지로 배열을 저장하기 위한 변수는 초깃값이 필요하지 않다.
변수시작은
undefined
로 시작
타입스크립트는 변수에 타입 애너테이션을 제공해 배열이 포함해야 하는 값의 타입을 알려준다
let arrayOfNumbers: number[]; arrayOfNumbers = [4, 8, 15, 16, 23, 42];
6.1.1 배열과 함수 타입
배열 타입 : 함수 타입에 무엇이 있는지를 구별하는 괄호가 필요한 구문 컨테이너
괄호: 애너테이션의 어느 부분이 함수 반환 부분이며 어느 부분이 배열 묶음인지를 나타냄
// 타입은 string 배열을 반환하는 함수
let createStrings: () => string[];
// 타입은 각각의 string을 반환하는 함수 배열
let stringCreators: (() => string)[];
6.1.2 유니언 타입 배열
배열 각 요소가 여러 선택 타입 중 하나임을 나타낼때는 유니언 타입 사용
괄호: 애너테이션의 어느 부분이 배열의 콘텐츠이고 어느 부분이 유니언 타입 묶음인지를 나타냄
타입스크립트는 배열 선언에서 두가지 이상의 요소 타입이 포함되는 경우 유니언 타입 배열임을 알 수 있다.
// 타입은 string 또는 number의 배열
let stringOrArrayOfNumbers: string | number[];
//타입은 각각 number 또는 string인 요소의 배열
let arrayOfStringOrNumbers: (string | number)[];
//타입: (string | undefined)[]
const namesMaybe = [
"Aqualtune",
"Blenda",
undefined,
];
6.1.3 any 배열의 진화
초기에 빈 배열로 설정된 변수에 타입 애너테이션을 포함하지 않을 시 배열을 any[]로 받는다.
any 타입이 되도록 허용하면 타입스크립트의 타입 검사 목적을 부분적으로 무효화시키게 된다.(권장x)
//타입: any[]
let values = [];
//타입: string[]
value.push('');
//타입: (number | string)[]
values[0] = 0;
6.1.4 다차원 배열
2차원 배열 또는 배열의 배열은 두개의 []를 갖는다.
3차원은 세개의 []를 가지며 6차원은 6개의 []를 가져 그 이상 배열에는 몇개의 []가 필요한지 예측할 수 있다.
원래의 타입을 가지며 끝에 []가 있고 그 뒤에 []를 추가한다
let arrayOfArraysOfNumbers = number[][];
arrayOfArraysOfNumbers = [
[1, 2, 3],
[2, 4, 6],
[3, 6, 9],
];
해당 다차원 배열은 다음과 같이 표현할수도 있다.
//타입: number[][]
let arrayOfArraysOfNumbers: (number[])[];
6.2 배열 멤버
타입스크립트는 배열의 멤버를 찾아 해당 배열의 타입요소를 되돌려주는 인덱스 기반 접근 방식
//타입: string[]
const defenders = ["Clarenza", "Dina"];
//타입: string
const defender = defenders[0];
유니언 타입으로 된 배열의 멤버는 자체로 동일한 유니언 타입
//soldierOrDates는 (string | Date)[] 타입이며 soldierOrDate는 string | Date 타입
const soldierOrDates = ["Deborah Sampson", new Date(1782, 6, 3)];
//타입: string | Date
const soldeirOrDate = soldiersOrDates[0];
6.3 스프레드와 나머지 매개변수
6.3.1 스프레드
스프레드: …스프레드 연산자를 사용해 배열을 결합하며 입력된 배열 중 하나의 값이 결과 배열에 포함될 것을 표시
입력된 배열이 동일한 타입일 시 출력 배열도 동일한 타입
서로 다른 타입의 두 배열을 통해 새 배열 생성 시 새 배열은 두개의 원래 타입 중 어느 하나의 요소인 유니언 타입 배열
/타입: string[]
const soldiers = ["Harriet Tubman", "Joan of Arc", "Khutulun"];
//타입: number[]
const soldierAges = [90, 19, 45];
//타입: (string | number)[]
//string 타입과 number타입 값을 모두 포함
const conjoined = [...soldiers, ...soldeirAges];
6.3.2 나머지 매개변수 스프레드
타입스크립트는 나머지 매개변수로 배열을 스프레드하는 자바스크립트 실행 인식 및 타입 검사를 수행한다.
나머지 매개변수에 인수로 사용되는 배열은 나머지 매개변수와 동일한 배열타입이여야 한다.
// …names 나머지 매개변수에는 string 값만 받으며 string[] 타입 배열을 스프레드 하는 것은 허용,
// number[]는 허용되지 않는다.
function logWarriors(greeting: string, ...names: string[] {
for (const name of names) {
console.log('${greeting}, ${name}!');
}
}
const warriors = ["Cathy Williams", "Lozen", "Nzinga"];
logWarriors("Hello", ...warriors);
const birthYears = [1844, 1840, 1583];
logWarriors("Born in", ...birthYears);
// Error: Argument of type 'number' is not assignable to parameter of type 'string'
6.4 튜플
자바스크립트 배열은 이론상 어떤 크기라도 될 수 있지만 때로는 고정된 크기의 배열을 사용하는 튜플을 사용하는 것이 유용하다.
튜플 배열은 각 인덱스에 알려진 특정 타입을 가지고 유니언 타입보다 더 구체적이다.
튜플 타입을 선언하는 구문은 요소의 값 대신 타입을 적는다.
//인덱스 0에 number 타입을 갖고 인덱스 1에 string 값을 갖는 튜플 타입 선언
let yearAndWarrior: [number, string];
yearAndWarrior = [530, "Tomyris"]; // Ok
yearAndWarrior = [false, "Tomyris"];
//Error: Type 'boolean' is not assignable to type 'number'
yearAndWarrior = [530];
//Error: Type '[number]' is not assignable to type '[number, string]'.
// Source has 1 element(s) but target requires 2
한번에 여러 값을 할당하기 위해 튜플과 배열 구조 분해할당을 함께 자주 사용한다.
// year 타입: 항상 number로 인식
// warrior 타입: 항상 string로 인식
let [year, warrior] = Math.random() > 0.5
? [340, "Archidamia"]
: [1828, "Rani of Jhansi"];
6.4.1 튜플 할당 가능성
타입스크립트에서 튜플 타입은 가변길이의 배열 타입보다 구체적으로 처리되며 가변 길이의 배열 타입은 튜플 타입에 할당할 수 없다.
우리눈에는
[boolean, number]
를 바로 볼 수 있지만 타입스크립트는 일반적인(boolean | number)[]
타입으로 유추한다.
//타입: (boolean | number)[]
const pairLoose = [false, 123];
const pairTupleLoose: [boolean, number] = pairLoose;
//Error: Type '(number | boolean)[]' is not assignable to type '[boolean, number]'.
//Target requires 2 element(s) but source may have fewer.
//타입스크립트는 튜플 타입의 튜플에 얼마나 많은 멤버가 있는지 알고 있기에 길이가 다른 튜플은 서로 할당 X
const tupleThree: [boolean, number, string] = [false, 1583, "Nzinga"];
const tupleTwoExact: [boolean, number] = [tupleThree[0], tupleThree[1]];
const tupleTwoExtra: [boolean, number] = tupleThree;
// Error: Type '[boolean, number, string]' is not assignable to type '[boolean,
// number]'.
// Source has 3 element(s) but target allows only 2.
// tupleTwoExtra는 정확히 두개의 멤버를 가져야 하기에 tupleThree가 올바른 멤버로 시작하여도
// 세번째 멤버는 tupleTwoExtra에 할당할 수 없다.
나머지 매개변수로서의 튜플
튜플은 함수에 전달할 인수를 저장하는데 유용하다.
타입스크립트는 … 나머지 매개변수로 전달된 튜플에 정확한 타입 검사를 제공할 수 있다.
//(string | number)[] 타입의 값을 인수로 전달하려고 할 시 둘 다 동일한 타입이거나 타입의 잘못된
//순서로 인해 내용이 일치하지 않을 가능성 때문에 타입의 안전 보장 X
//값이[string, number] 튜플이라고 알 시 값이 일치하다는 것을 알 수 있다.
function logPair(name: string, value: number) {
console.log('${name} has ${value}');
}
const pairArray = ["Amage", 1];
logPair(...pairArray);
//Error: A spread argument must either have a tuple type or be passed to a rest
//parameter.
const pairTupleIncorrect: [number, string] = [1, "Amage"];
logPair(...pairTupleIncorrect);
//Error: Argument of type 'number' is not assignable to parameter of type 'string'.
const pairTupleCorrect: [string, number] = ["Amage", 1];
logPair(...pairTupleCorrect); //Ok
//나머지 매개변수 튜플을 사용할시 여러 번 함수를 호출하는 인수 목록을 배열에 저장하여 함께 사용가능
function logTrio(name: string, value: [number, boolean]) {
console.log('${name} has ${value[0]} (${value[1]}');
}
//튜플 배열, 각 배열은 두번째 멤버로 튜플을 가지는 구조
const trios: [string, [number, boolean]][] = [
["Amanitore", [1, true]],
["AEthelflaed", [2, false]],
["Ann E. Dunwoody", [3, false]],
];
//각 ...trio가 logTrio의 매개변수 타입과 일치하므로 통과
trios.forEach(trio => logTrio(...trio)); //Ok
//첫 번째 매개변수로 타입이 string인 [string, [number, boolean]] 전체를 전달하려고 시도하기에
//할당 X
trios.forEach(logTrio);
//Error: Argument of type '(name: string, value: [number, boolean]) => void' is not
// assignable to parameter of type '(value: [string, [number, boolean]], ...) => void'.
// Types of parameters 'name' and 'value' are incompatible
// Type '[string, [number, boolean]]' is not assignable to type 'string'.
6.4.2 튜플 추론
타입스크립트는 생성된 배열을 튜플이 아닌 가변 길이의 배열로 취급
배열의 변수의 초깃값 또는 함수에 대한 반환값으로 사용될 경우, 유연한 크기의 튜플 배열로 가정한다.
타입스크립트에서는 값이 일반적인 배열 타입 대신 구체적인 튜플 타입이어야 함을 나타낸다
명시적 튜플 타입
const 어서션
// [string, number]가 아니라 (string | number)[]를 반환하는 것으로 유추 // 반환 타입: (string | number)[] function firstCharAndSize(input: string) { return [input[0], input.length]; } // firstChar 타입: string | number // size 타입: string | number const [firstChar, size] = firstCharAndSize("Gudit");
명시적 튜플 타입
튜플 타입도 타입 애너테이션에 사용할 수 있다.
함수가 튜플 타입을 반환하다고 선언 및 배열 리터럴을 반환한다면 해당 배열 리터럴은 일반적인 가변길이의 배열 대신 튜플로 간주된다.
//반환 타입: [string, number] function firstCharAndSizeExplicit(input: string): [string, number] { return [input[0], input.length]; } // firstChar 타입: string // size 타입: number const [firstChar, size] = firstCharAndSizeExplicit("Cathy Williams");
const 어서션
타입스크립트는 값 뒤에 넣을 수 있는 const 어서션인 as const 연산자를 제공
const 어서션은 타입스크립트에 타입을 유추할 때 read-only가 가능한 값 형식을 사용하도록 지시
//타입: (string | number)[] const unionArray = [1157, "Tomoe"]; //타입: readonly [1157, "Tomoe"] //배열이 튜플로 처리되어야 함을 나타낸다. const readonlyTuple = [1157, "Tomoe"] as const;
유연한 크기의 배열을 고정된 크기의 튜플을 전환하는 것 이외 해당 튜플이 read-only이며 값 수정이 예상되는 곳에서는 사용될 수 없을을 나타낸다.
//pairMutable은 명시적 튜플 타입이어서 수정될 수 있다. //하지만 as const는 값이 변경될 수 있는 pairAlsoMutable에 할당할 수 없도록 하며, //상수 pairConst의 멤버는 수정을 허용하지 않는다. const pairMutable: [number, string] = [1157, "Tomoe"]; pariMutable[0] = 1247; Ok const pairAlsoMutable: [number, string] = [1157, "Tomoe"] as const; //Error: The type 'readonly [1157, "Tomoe"]' is 'readonly' // and cannot be assigned to the mutable type '[number, string]'. const pairConst = [1157, "Tomoe"] as const; pairConst[0] = 1247; //Error: Cannot assign to '0' because it is a read-only property.
튜플을 반환하는 함수로부터 반환된 값은 보통 즉시 구조화되지 않기에 read-only 전용인 튜플은 함수를 사용하는데 방해가 되지 않는다.
//반환타입: readonly [string, number] //읽기 전용 [string, number]를 반환하지만, 해당 함수를 사용하는 코드에서는 해당 튜플에서 값을 //찾는것에만 관심을 둔다. function firstCharAndSizeAsConst(input: string) { return [input[0], input.length] as const; } //firstChart 타입: string //size타입 : number const [firstChar, size] = firstCharAndSizeAsConst("Ching Shih");