목차
배열과 튜플 제대로 이해하기
지난 시간에는 값이 없는 상태를 표현하는 `null`과 `undefined`를 살펴봤습니다.
let selectedUser: string | null = null;
let message: string | undefined;그런데 프로그램에서 관리해야 하는 값은 대부분 하나가 아닙니다.
학생 한 명의 점수만 저장한다면 변수 하나로 충분합니다.
const score = 90;하지만 학생 100명의 점수를 저장하려면 어떻게 해야 할까요?
const score1 = 90;
const score2 = 85;
const score3 = 100;
const score4 = 75;학생이 늘어날 때마다 변수를 추가하면 교실보다 변수 이름표가 더 붐비기 시작합니다.
상품 목록, 사용자 목록, 게시글 목록처럼 여러 데이터를 관리하려면 배열(Array)이 필요합니다.
const scores = [90, 85, 100, 75];배열은 여러 값을 한 줄로 세워 하나의 변수로 관리할 수 있게 해줍니다.
그런데 배열과 비슷하게 생겼지만 조금 더 엄격한 타입도 있습니다.
const userInfo: [string, number] = [
"김타입",
25,
];이것을 튜플(Tuple)이라고 합니다.
배열이 자유석 버스라면 튜플은 좌석 번호가 적힌 열차입니다. 🚆
배열에서는 같은 타입의 승객들이 자유롭게 앉을 수 있지만, 튜플에서는 첫 번째 좌석과 두 번째 좌석의 승객 타입이 정해져 있습니다.
이번 시간에는 배열과 튜플의 차이를 하나씩 살펴보겠습니다.
1. 이번 시간에 배울 내용
이번 시간에는 다음 내용을 알아봅니다.
- 배열은 무엇인가?
- TypeScript에서 배열 타입을 작성하는 방법
- `number[]`와 `Array<number>`의 차이
- 배열 요소에 접근하고 변경하는 방법
- 배열에 값을 추가하고 제거하는 방법
- `map()`, `filter()`, `find()` 사용하기
- 객체 배열 다루기
- 읽기 전용 배열 만들기
- 튜플은 무엇인가?
- 배열과 튜플의 차이
- 선택적 튜플과 나머지 요소
- 읽기 전용 튜플
- 구조 분해 할당과 튜플
- 배열과 튜플을 선택하는 기준
오늘의 등장인물은 두 종류의 데이터 보관함입니다.
배열 : 같은 종류의 물건을 자유롭게 보관하는 창고
튜플 : 각 칸의 용도가 정해진 맞춤형 보관함이제 여러 데이터를 정리하는 TypeScript의 수납 기술을 시작해 보겠습니다. 📦
2. 배열이란?
배열은 여러 개의 값을 하나의 변수에 저장할 수 있는 자료구조입니다.
const scores = [90, 85, 100];`scores` 배열에는 숫자 세 개가 들어 있습니다.
90
85
100각 값을 따로 변수로 만들 필요가 없습니다.
const score1 = 90;
const score2 = 85;
const score3 = 100;배열을 사용하면 하나의 이름으로 여러 값을 관리할 수 있습니다.
const scores = [90, 85, 100];배열 안에 들어 있는 각각의 값을 요소(Element)라고 부릅니다.
배열: [90, 85, 100]
요소 1: 90
요소 2: 85
요소 3: 100배열은 대괄호 `[]`를 사용해 만듭니다.
const 배열이름 = [값1, 값2, 값3];3. TypeScript가 배열 타입을 추론하는 방법
TypeScript는 배열 안에 들어 있는 값을 보고 배열의 타입을 추론할 수 있습니다.
const scores = [90, 85, 100];모든 요소가 숫자이므로 TypeScript는 다음 타입으로 추론합니다.
number[]문자열 배열도 자동으로 추론됩니다.
const languages = [
"JavaScript",
"TypeScript",
"Python",
];추론된 타입은 다음과 같습니다.
string[]불리언 배열도 마찬가지입니다.
const answers = [
true,
false,
true,
];추론 타입:
boolean[]TypeScript는 배열의 입구에서 첫 손님들만 봐도 어떤 모임인지 파악합니다.
숫자들만 들어오면 숫자 전용 모임, 문자열들만 들어오면 문자열 동호회로 등록합니다.
4. 배열 타입을 직접 작성하는 첫 번째 방법
배열 타입은 요소 타입 뒤에 대괄호를 붙여 작성할 수 있습니다.
const scores: number[] = [
90,
85,
100,
];문자열 배열은 다음과 같습니다.
const languages: string[] = [
"JavaScript",
"TypeScript",
];불리언 배열도 만들 수 있습니다.
const permissions: boolean[] = [
true,
false,
true,
];형식은 간단합니다.
요소타입[]예를 들어 다음과 같습니다.
number[] : 숫자 배열
string[] : 문자열 배열
boolean[] : 불리언 배열5. 배열 타입을 직접 작성하는 두 번째 방법
TypeScript에서는 `Array<타입>` 문법으로도 배열 타입을 작성할 수 있습니다.
const scores: Array<number> = [
90,
85,
100,
];문자열 배열은 다음처럼 작성합니다.
const languages: Array<string> = [
"JavaScript",
"TypeScript",
];두 가지 문법은 같은 의미입니다.
number[]
Array<number>모두 숫자 배열입니다.
string[]
Array<string>모두 문자열 배열입니다.
6. `number[]`와 `Array<number>`는 무엇이 다를까?
기능상 큰 차이는 없습니다.
const firstScores: number[] = [
90,
80,
];
const secondScores: Array<number> = [
90,
80,
];두 배열 모두 숫자만 저장할 수 있습니다.
일반적으로 단순한 배열에는 `타입[]` 문법이 많이 사용됩니다.
string[]
number[]
boolean[]`Array<타입>`은 제네릭 문법을 보여주거나 복잡한 타입을 표현할 때 사용하기도 합니다.
Array<string>
Array<number>초보 단계에서는 다음처럼 기억하면 충분합니다.
타입[] : 짧고 자주 사용됨
Array<타입> : 같은 의미의 또 다른 표현프로젝트 안에서는 한 가지 방식을 일관되게 사용하는 것이 좋습니다.
배열에게 옷을 두 벌 입힐 수 있지만, 월요일마다 문법을 바꿀 필요는 없습니다.
7. 배열에 잘못된 타입을 넣으면?
다음 배열은 숫자 배열입니다.
const scores: number[] = [
90,
85,
100,
];숫자를 추가하는 것은 가능합니다.
scores.push(95);하지만 문자열을 추가하면 오류가 발생합니다.
scores.push("만점");오류 메시지는 다음과 비슷합니다.
Argument of type 'string' is not assignable
to parameter of type 'number'.숫자 배열에는 숫자만 들어갈 수 있다는 뜻입니다.
다음 코드도 오류입니다.
scores[0] = "구십 점";올바른 코드는 다음과 같습니다.
scores[0] = 90;TypeScript의 배열은 입구에서 신분증을 검사합니다.
숫자 전용 행사장에 `"만점"`이라는 문자열이 정장 차림으로 나타나도 입장할 수 없습니다.
8. 빈 배열의 타입은 직접 작성하자
처음에는 비어 있지만 나중에 값을 추가할 배열이 있습니다.
const scores = [];빈 배열만 보면 TypeScript는 어떤 종류의 값이 들어올지 정확히 알기 어렵습니다.
프로젝트 설정과 사용 흐름에 따라 타입이 예상과 다르게 추론될 수 있습니다.
따라서 빈 배열에는 타입을 직접 작성하는 것이 안전합니다.
const scores: number[] = [];이제 숫자만 추가할 수 있습니다.
scores.push(90);
scores.push(85);문자열은 추가할 수 없습니다.
scores.push("만점");문자열 배열도 같은 방식으로 작성합니다.
const todoList: string[] = [];todoList.push("TypeScript 공부");
todoList.push("배열 복습");빈 상자를 준비할 때는 상자 바깥에 무엇을 넣을 상자인지 라벨을 붙여두는 것이 좋습니다.
숫자 전용
문자열 전용
불리언 전용라벨 없는 상자는 시간이 지나면 정체불명의 케이블 창고가 되기 쉽습니다.
9. 배열 요소의 위치 번호
배열의 각 요소에는 위치 번호가 있습니다.
이 번호를 인덱스(Index)라고 부릅니다.
const languages = [
"JavaScript",
"TypeScript",
"Python",
];각 요소의 인덱스는 다음과 같습니다.
JavaScript TypeScript Python
0 1 2배열의 인덱스는 `0`부터 시작합니다.
console.log(languages[0]);
console.log(languages[1]);
console.log(languages[2]);출력 결과:
JavaScript
TypeScript
Python첫 번째 요소를 가져올 때 `[1]`이 아니라 `[0]`을 사용해야 합니다.
const firstLanguage = languages[0];프로그래밍 세계는 첫 번째 손님에게 0번 번호표를 줍니다.
현실의 번호표 시스템과 달라서 처음에는 약간 억울하지만, 곧 익숙해집니다.
10. 존재하지 않는 인덱스에 접근하면?
배열에 존재하지 않는 위치를 읽어 보겠습니다.
const languages = [
"JavaScript",
"TypeScript",
];
console.log(languages[10]);실행 결과는 다음과 같습니다.
undefined10번 위치에는 값이 없기 때문입니다.
기본 설정에서는 TypeScript가 배열 접근 결과를 단순히 `string`으로 추론할 수 있습니다.
하지만 실제 실행에서는 인덱스가 범위를 벗어나면 `undefined`가 나옵니다.
더 엄격하게 검사하려면 `tsconfig.json`에서 다음 옵션을 사용할 수 있습니다.
{
"compilerOptions": {
"noUncheckedIndexedAccess": true
}
}이 옵션을 켜면 배열 요소 접근 결과에 `undefined` 가능성이 포함됩니다.
const language = languages[10];개념적인 타입:
string | undefined따라서 사용 전에 확인해야 합니다.
if (language !== undefined) {
console.log(language.toUpperCase());
}배열의 복도 끝에 없는 방 번호를 열었을 때, TypeScript가 “그 방은 없을 수도 있습니다”라고 알려주는 설정입니다.
11. 배열 요소 변경하기
`const`로 배열을 선언해도 배열 내부의 요소는 변경할 수 있습니다.
const scores: number[] = [
90,
85,
100,
];
scores[1] = 95;변경된 배열:
[90, 95, 100]그런데 `const`인데 왜 수정할 수 있을까요?
`const`는 변수에 다른 배열을 다시 할당하지 못하게 합니다.
scores = [70, 80, 90];이 코드는 오류가 발생합니다.
하지만 배열 내부의 요소를 변경하는 것은 허용됩니다.
scores[0] = 70;
scores.push(80);정리하면 다음과 같습니다.
const 배열 변수
배열 자체를 다른 배열로 교체할 수 없음
배열 내부 요소는 변경할 수 있음`const`는 창고 건물을 다른 건물로 바꾸지 못하게 할 뿐, 창고 안의 상자를 재배치하는 것까지 막지는 않습니다.
12. 배열의 길이 확인하기
배열의 요소 개수는 `length` 속성으로 확인할 수 있습니다.
const scores = [
90,
85,
100,
];
console.log(scores.length);출력 결과:
3빈 배열의 길이는 `0`입니다.
const emptyArray: number[] = [];
console.log(emptyArray.length);출력 결과:
0마지막 요소의 인덱스는 배열 길이보다 1 작습니다.
const lastIndex = scores.length - 1;
const lastScore = scores[lastIndex];
console.log(lastScore);출력 결과:
10013. 배열 끝에 값 추가하기
배열 끝에 값을 추가할 때 `push()`를 사용합니다.
const languages: string[] = [
"JavaScript",
"TypeScript",
];
languages.push("Python");변경된 배열:
["JavaScript", "TypeScript", "Python"]한 번에 여러 값을 추가할 수도 있습니다.
languages.push("Java", "C#");`push()`는 변경된 배열 길이를 반환합니다.
const newLength =
languages.push("Go");
console.log(newLength);배열 끝에 새로운 객차를 연결하는 작업이라고 생각하면 됩니다. 🚃
14. 배열 끝의 값 제거하기
배열 마지막 값을 제거할 때 `pop()`을 사용합니다.
const languages: string[] = [
"JavaScript",
"TypeScript",
"Python",
];
const removedLanguage =
languages.pop();`removedLanguage`에는 제거된 값이 들어갑니다.
console.log(removedLanguage);출력 결과:
Python남은 배열:
["JavaScript", "TypeScript"]빈 배열에서 `pop()`을 호출하면 `undefined`를 반환합니다.
const emptyArray: string[] = [];
const removedValue =
emptyArray.pop();
console.log(removedValue);출력 결과:
undefined따라서 반환 타입은 다음과 비슷합니다.
string | undefined지난 시간에 배운 `undefined`가 다시 등장했습니다.
배열 끝에서 꺼낼 물건이 없다면 TypeScript는 빈손으로 돌아옵니다.
15. 배열 앞에 값 추가하기
배열 앞에 값을 추가할 때 `unshift()`를 사용합니다.
const numbers: number[] = [
20,
30,
];
numbers.unshift(10);결과:
[10, 20, 30]한 번에 여러 값을 추가할 수도 있습니다.
numbers.unshift(-10, 0);결과:
[-10, 0, 10, 20, 30]16. 배열 앞의 값 제거하기
배열 첫 번째 값을 제거할 때 `shift()`를 사용합니다.
const numbers: number[] = [
10,
20,
30,
];
const removedNumber =
numbers.shift();`removedNumber`에는 `10`이 들어갑니다.
남은 배열:
[20, 30]빈 배열에서 호출하면 `undefined`를 반환할 수 있습니다.
const emptyNumbers: number[] = [];
const value = emptyNumbers.shift();`value`의 타입:
number | undefined17. 배열의 주요 추가·삭제 메서드 정리
| 메서드 | 동작 |
|---|---|
| `push()` | 배열 끝에 추가 |
| `pop()` | 배열 끝에서 제거 |
| `unshift()` | 배열 앞에 추가 |
| `shift()` | 배열 앞에서 제거 |
예제를 한 번에 살펴보겠습니다.
const queue: string[] = [];
queue.push("김타입");
queue.push("이컴파일");
console.log(queue);
const firstUser = queue.shift();
console.log(firstUser);
console.log(queue);출력 결과:
["김타입", "이컴파일"]
김타입
["이컴파일"]`push()`와 `shift()`를 함께 사용하면 먼저 들어온 값이 먼저 나가는 대기열을 만들 수 있습니다.
은행 번호표 시스템처럼 줄을 서는 구조입니다.
18. 반복문으로 배열 순회하기
배열의 모든 요소를 하나씩 처리할 때 반복문을 사용할 수 있습니다.
const languages: string[] = [
"JavaScript",
"TypeScript",
"Python",
];일반 `for`문을 사용해 보겠습니다.
for (
let index = 0;
index < languages.length;
index++
) {
console.log(languages[index]);
}출력 결과:
JavaScript
TypeScript
Python`for...of` 문을 사용하면 더 간단합니다.
for (const language of languages) {
console.log(language);
}`language`는 자동으로 `string` 타입으로 추론됩니다.
language.toUpperCase();배열이 문자열 배열이라는 사실을 TypeScript가 알고 있기 때문입니다.
19. `forEach()`로 배열 순회하기
`forEach()`는 배열의 각 요소마다 함수를 실행합니다.
const scores: number[] = [
90,
85,
100,
];
scores.forEach((score) => {
console.log(score);
});`score`는 자동으로 `number` 타입으로 추론됩니다.
인덱스도 함께 받을 수 있습니다.
scores.forEach((score, index) => {
console.log(
`${index + 1}번째 점수: ${score}`
);
});출력 결과:
1번째 점수: 90
2번째 점수: 85
3번째 점수: 100`forEach()`는 배열을 돌며 작업을 수행하지만 새로운 배열을 반환하지 않습니다.
주로 출력, 로그 기록, 외부 작업 실행 등에 사용합니다.
20. `map()`으로 새로운 배열 만들기
`map()`은 배열의 각 요소를 변환해 새로운 배열을 만듭니다.
const numbers: number[] = [
1,
2,
3,
];
const doubledNumbers =
numbers.map((number) => {
return number * 2;
});`doubledNumbers`의 값:
[2, 4, 6]TypeScript는 반환값을 보고 새로운 배열 타입을 추론합니다.
number[]숫자 배열을 문자열 배열로 변환할 수도 있습니다.
const scoreMessages =
scores.map((score) => {
return `${score}점`;
});`scoreMessages`의 타입:
string[]결과:
["90점", "85점", "100점"]`map()`은 원래 배열을 직접 변경하지 않습니다.
console.log(scores);
console.log(scoreMessages);기존 배열을 복사해 각 요소에게 새로운 옷을 입혀 별도의 행렬을 만드는 셈입니다.
21. 화살표 함수로 `map()` 간단히 작성하기
반환문이 한 줄이라면 중괄호와 `return`을 생략할 수 있습니다.
const doubledNumbers =
numbers.map(
(number) => number * 2
);문자열도 만들 수 있습니다.
const messages =
scores.map(
(score) => `${score}점`
);객체 배열을 변환할 때도 자주 사용합니다.
const userNames =
users.map(
(user) => user.name
);22. `filter()`로 원하는 요소만 고르기
`filter()`는 조건을 만족하는 요소만 모아 새로운 배열을 만듭니다.
const scores: number[] = [
45,
80,
95,
60,
100,
];
const passedScores =
scores.filter((score) => {
return score >= 60;
});결과:
[80, 95, 60, 100]간단하게 작성할 수도 있습니다.
const passedScores =
scores.filter(
(score) => score >= 60
);`filter()`가 받는 콜백 함수는 `true` 또는 `false`를 반환합니다.
true → 새로운 배열에 포함
false → 새로운 배열에서 제외배열 입구에 조건문으로 된 체를 설치하고, 통과한 값만 새 바구니에 담는 방식입니다. 🧺
23. `find()`로 첫 번째 값 찾기
`find()`는 조건을 만족하는 첫 번째 요소를 반환합니다.
const scores: number[] = [
45,
80,
95,
60,
];
const highScore =
scores.find(
(score) => score >= 90
);결과:
95조건을 만족하는 값이 없으면 `undefined`를 반환합니다.
const perfectScore =
scores.find(
(score) => score === 100
);`perfectScore`의 타입은 다음과 같습니다.
number | undefined따라서 안전하게 확인한 뒤 사용해야 합니다.
if (perfectScore !== undefined) {
console.log(
`만점을 찾았습니다: ${perfectScore}`
);
} else {
console.log("만점이 없습니다.");
}기본값을 사용하려면 `??`를 사용할 수 있습니다.
const score =
perfectScore ?? 0;24. `filter()`와 `find()`의 차이
두 메서드는 비슷해 보이지만 반환 결과가 다릅니다.
const numbers = [
10,
20,
30,
40,
];`filter()`는 조건에 맞는 모든 요소를 배열로 반환합니다.
const filtered =
numbers.filter(
(number) => number >= 20
);결과:
[20, 30, 40]`find()`는 첫 번째 요소 하나만 반환합니다.
const found =
numbers.find(
(number) => number >= 20
);결과:
20정리하면 다음과 같습니다.
| 메서드 | 반환 결과 |
|---|---|
| `filter()` | 조건에 맞는 요소의 배열 |
| `find()` | 조건에 맞는 첫 번째 요소 |
| `find()` 실패 | `undefined` |
25. `some()`과 `every()`
배열 안에 조건을 만족하는 요소가 있는지 확인할 수도 있습니다.
하나라도 만족하는지 확인
`some()`은 하나라도 조건을 만족하면 `true`를 반환합니다.
const scores = [
40,
55,
90,
];
const hasHighScore =
scores.some(
(score) => score >= 90
);
console.log(hasHighScore);출력 결과:
true모두 만족하는지 확인
`every()`는 모든 요소가 조건을 만족해야 `true`를 반환합니다.
const allPassed =
scores.every(
(score) => score >= 60
);
console.log(allPassed);출력 결과:
falsesome() : 한 명이라도 통과했는가?
every() : 전원이 통과했는가?배열 심사위원 두 명의 성격이 꽤 다릅니다.
한 명은 한 명만 잘해도 박수를 치고, 다른 한 명은 전원 합격 전까지 팔짱을 풀지 않습니다.
26. `includes()`로 값 포함 여부 확인하기
배열에 특정 값이 있는지 확인할 때 `includes()`를 사용할 수 있습니다.
const languages: string[] = [
"JavaScript",
"TypeScript",
"Python",
];
const hasTypeScript =
languages.includes("TypeScript");
console.log(hasTypeScript);출력 결과:
true없는 값을 확인하면 `false`입니다.
console.log(
languages.includes("Java")
);출력 결과:
false27. 객체 배열 만들기
실제 프로그램에서는 숫자나 문자열보다 객체 배열을 자주 사용합니다.
사용자 타입을 만들어 보겠습니다.
type User = {
id: number;
name: string;
isActive: boolean;
};사용자 배열을 만듭니다.
const users: User[] = [
{
id: 1,
name: "김타입",
isActive: true,
},
{
id: 2,
name: "이컴파일",
isActive: false,
},
{
id: 3,
name: "박제네릭",
isActive: true,
},
];`users`는 `User` 객체만 저장할 수 있는 배열입니다.
잘못된 속성 타입을 넣으면 오류가 발생합니다.
users.push({
id: "4",
name: "최배열",
isActive: true,
});`id`는 숫자여야 하지만 문자열이므로 오류입니다.
28. 객체 배열에서 값 찾기
`find()`를 사용해 특정 사용자를 찾을 수 있습니다.
const user =
users.find(
(user) => user.id === 2
);찾은 사용자가 있을 수도 있고 없을 수도 있습니다.
따라서 타입은 다음과 같습니다.
User | undefined안전하게 확인합니다.
if (user !== undefined) {
console.log(user.name);
}선택적 연결 연산자를 사용할 수도 있습니다.
console.log(user?.name);기본값까지 적용해 보겠습니다.
const userName =
user?.name ?? "사용자 없음";7편에서 배운 `?.`와 `??`가 배열에서도 다시 활약합니다.
TypeScript의 기능들은 각자 따로 노는 부품이 아니라 레고 블록처럼 계속 연결됩니다. 🧱
29. 객체 배열에서 데이터 변환하기
사용자 이름만 모은 배열을 만들 수 있습니다.
const userNames =
users.map(
(user) => user.name
);결과:
["김타입", "이컴파일", "박제네릭"]타입:
string[]활성 사용자만 선택할 수도 있습니다.
const activeUsers =
users.filter(
(user) => user.isActive
);결과는 `User[]` 타입입니다.
활성 사용자 이름만 바로 만들 수도 있습니다.
const activeUserNames =
users
.filter(
(user) => user.isActive
)
.map(
(user) => user.name
);배열 메서드를 연결해 사용하는 것을 메서드 체이닝이라고 합니다.
활성 사용자 선택
↓
사용자 이름만 추출다만 너무 많은 메서드를 한 줄에 연결하면 코드가 읽기 어려워질 수 있습니다.
복잡한 작업은 중간 변수로 나누는 것도 좋은 방법입니다.
30. 배열 복사하기
배열을 다른 변수에 그대로 할당하면 같은 배열을 바라보게 됩니다.
const original = [1, 2, 3];
const copied = original;`copied`를 수정하면 `original`도 변경됩니다.
copied.push(4);
console.log(original);출력 결과:
[1, 2, 3, 4]실제로 복사본을 만들려면 전개 연산자 `...`를 사용할 수 있습니다.
const original = [1, 2, 3];
const copied = [...original];
copied.push(4);이제 결과가 다릅니다.
console.log(original);
console.log(copied);출력 결과:
[1, 2, 3]
[1, 2, 3, 4]`...`는 배열 안의 요소를 꺼내 새 배열에 펼쳐 놓습니다.
복사기를 사용하지 않고 원본 창고 열쇠를 한 개 더 만든 것인지, 실제 새 창고를 만든 것인지 구분해야 합니다.
31. 배열 합치기
전개 연산자를 사용해 여러 배열을 합칠 수 있습니다.
const frontend = [
"HTML",
"CSS",
"JavaScript",
];
const backend = [
"Node.js",
"Java",
"Python",
];
const technologies = [
...frontend,
...backend,
];결과:
[
"HTML",
"CSS",
"JavaScript",
"Node.js",
"Java",
"Python"
]`concat()` 메서드를 사용할 수도 있습니다.
const technologies =
frontend.concat(backend);32. 읽기 전용 배열
배열을 만든 뒤 요소를 변경하지 못하게 하고 싶을 수 있습니다.
이럴 때 `readonly`를 사용할 수 있습니다.
const languages:
readonly string[] = [
"JavaScript",
"TypeScript",
];배열 요소를 변경하려 하면 오류가 발생합니다.
languages[0] = "Python";값을 추가할 수도 없습니다.
languages.push("Python");`push()` 같은 변경 메서드를 사용할 수 없기 때문입니다.
`ReadonlyArray<타입>` 문법도 사용할 수 있습니다.
const scores:
ReadonlyArray<number> = [
90,
85,
100,
];읽기 전용 배열은 조회는 가능하지만 수정은 불가능합니다.
console.log(scores[0]);
console.log(scores.length);설정값, 고정된 목록, 함수가 받아서 읽기만 해야 하는 데이터에 유용합니다.
33. 함수 매개변수에 읽기 전용 배열 사용하기
함수가 배열을 읽기만 하고 수정해서는 안 된다면 읽기 전용 타입을 사용할 수 있습니다.
function calculateAverage(
scores: readonly number[]
): number {
const total = scores.reduce(
(sum, score) => sum + score,
0
);
return total / scores.length;
}함수 내부에서 배열을 수정할 수 없습니다.
function calculateAverage(
scores: readonly number[]
): number {
scores.push(100);
return 0;
}이 코드는 오류가 발생합니다.
함수의 계약서에 다음 문장이 적힌 셈입니다.
“이 배열은 열람만 가능하며 낙서와 요소 추가를 금지합니다.”
34. `reduce()`로 값을 하나로 합치기
`reduce()`는 배열의 여러 값을 하나의 결과로 누적합니다.
const scores = [
90,
85,
100,
];
const total = scores.reduce(
(sum, score) => {
return sum + score;
},
0
);결과:
275간단하게 작성할 수도 있습니다.
const total = scores.reduce(
(sum, score) => sum + score,
0
);평균을 계산합니다.
const average =
total / scores.length;
console.log(average);`reduce()`는 숫자 합계뿐 아니라 객체 생성, 데이터 분류 등에도 사용할 수 있습니다.
다만 초보자에게는 동작 방식이 조금 복잡하게 느껴질 수 있으므로, 처음에는 합계 계산부터 익히는 것이 좋습니다.
35. 여러 타입이 섞인 배열은 어떻게 될까?
다음 배열에는 숫자와 문자열이 함께 들어 있습니다.
const values = [
10,
"TypeScript",
20,
];TypeScript는 배열 요소가 숫자 또는 문자열이라고 추론합니다.
개념적인 타입은 다음과 같습니다.
(number | string)[]이런 배열에는 숫자와 문자열을 추가할 수 있습니다.
values.push(30);
values.push("JavaScript");하지만 불리언은 추가할 수 없습니다.
values.push(true);`number | string`처럼 여러 타입 중 하나를 허용하는 문법을 유니언 타입이라고 합니다.
유니언 타입은 다음 9편에서 자세히 다룰 예정입니다.
실무에서는 이유 없이 여러 타입을 한 배열에 섞는 것보다, 데이터 구조를 명확하게 설계하는 것이 좋습니다.
const scores: number[] = [
90,
85,
100,
];const messages: string[] = [
"성공",
"실패",
];냉장고 한 칸에 양말과 아이스크림을 함께 넣을 수는 있지만, 좋은 수납 방식은 아닙니다.
36. 튜플이란?
튜플은 요소의 개수와 위치별 타입이 정해진 배열입니다.
const userInfo:
[string, number] = [
"김타입",
25,
];이 튜플에는 정확히 두 개의 요소가 있습니다.
첫 번째 요소: string
두 번째 요소: number따라서 다음 구조를 지켜야 합니다.
[string, number]올바른 값:
["김타입", 25]잘못된 값:
[25, "김타입"]순서가 바뀌었기 때문에 오류가 발생합니다.
튜플은 같은 타입을 자유롭게 담는 일반 배열과 달리, 좌석별 승객 타입까지 지정합니다.
1번 좌석: 문자열
2번 좌석: 숫자2번 좌석에 문자열 승객이 앉으면 TypeScript 승무원이 즉시 찾아옵니다.
37. 배열과 튜플 비교하기
일반 배열을 살펴보겠습니다.
const userInfo: (string | number)[] = [
"김타입",
25,
];이 배열은 문자열과 숫자를 여러 개 저장할 수 있습니다.
다음 코드도 허용될 수 있습니다.
userInfo.push("서울");
userInfo.push(100);순서와 개수가 정해져 있지 않습니다.
반면 튜플은 다음과 같습니다.
const userInfo:
[string, number] = [
"김타입",
25,
];첫 번째 값은 문자열, 두 번째 값은 숫자여야 합니다.
정리하면 다음과 같습니다.
| 구분 | 배열 | 튜플 |
|---|---|---|
| 요소 개수 | 보통 가변적 | 정해진 구조 |
| 요소 타입 | 일반적으로 동일 | 위치마다 다를 수 있음 |
| 순서 의미 | 상대적으로 약함 | 매우 중요 |
| 사용 예 | 목록, 컬렉션 | 좌표, 함수 결과, 고정 구조 |
38. 튜플 요소 접근하기
튜플도 배열처럼 인덱스로 접근합니다.
const userInfo:
[string, number] = [
"김타입",
25,
];const userName = userInfo[0];
const age = userInfo[1];TypeScript는 위치별 타입을 정확하게 알고 있습니다.
userName; // string
age; // number문자열 메서드를 사용할 수 있습니다.
console.log(
userInfo[0].toUpperCase()
);숫자 계산도 가능합니다.
console.log(
userInfo[1] + 1
);일반적인 혼합 배열에서는 요소 타입을 확인해야 할 수 있지만, 튜플은 위치에 따라 타입이 확정됩니다.
39. 튜플의 순서가 중요한 이유
좌표를 튜플로 표현해 보겠습니다.
const position:
[number, number] = [
127.0,
37.5,
];두 값 모두 숫자이지만 각각 의미가 다릅니다.
첫 번째 값: 경도
두 번째 값: 위도RGB 색상도 튜플로 표현할 수 있습니다.
const redColor:
[number, number, number] = [
255,
0,
0,
];각 위치의 의미:
0번: 빨강
1번: 초록
2번: 파랑HTTP 응답의 간단한 결과도 표현할 수 있습니다.
const response:
[number, string] = [
200,
"성공",
];첫 번째 값: 상태 코드
두 번째 값: 메시지튜플은 값의 순서 자체가 의미를 가질 때 유용합니다.
40. 이름이 붙은 튜플 요소
TypeScript에서는 튜플 요소에 이름을 붙여 의미를 표시할 수 있습니다.
type UserInfo = [
name: string,
age: number,
];사용 방법은 같습니다.
const user:
UserInfo = [
"김타입",
25,
];이름은 코드 실행에 영향을 주지 않지만 개발 도구에서 각 위치의 의미를 이해하기 쉬워집니다.
좌표 튜플에도 이름을 붙일 수 있습니다.
type Coordinate = [
latitude: number,
longitude: number,
];const seoul: Coordinate = [
37.5665,
126.978,
];이름 없는 좌석표에 용도를 적어 놓은 셈입니다.
1번 좌석: latitude
2번 좌석: longitude41. 선택적 튜플 요소
튜플의 일부 요소는 선택 사항으로 만들 수 있습니다.
type UserInfo = [
name: string,
age: number,
nickname?: string,
];두 개의 값만 사용할 수 있습니다.
const firstUser: UserInfo = [
"김타입",
25,
];닉네임까지 넣을 수도 있습니다.
const secondUser: UserInfo = [
"이컴파일",
30,
"컴파일러",
];선택적 요소는 필수 요소 뒤에 위치해야 합니다.
다음 구조는 사용할 수 없습니다.
type WrongTuple = [
name?: string,
age: number,
];선택적인 첫 번째 값이 빠지면 두 번째 값의 위치를 해석하기 어려워지기 때문입니다.
튜플의 선택석은 일반석 뒤쪽에 배치해야 합니다.
42. 튜플의 나머지 요소
튜플 뒤에 같은 타입의 값이 여러 개 이어질 수 있다면 나머지 요소 문법을 사용할 수 있습니다.
type StudentScores = [
name: string,
...scores: number[],
];첫 번째 요소는 학생 이름입니다.
그 뒤에는 숫자 점수가 여러 개 올 수 있습니다.
const student: StudentScores = [
"김타입",
90,
85,
100,
];다음 코드도 가능합니다.
const student: StudentScores = [
"이컴파일",
];학생 이름은 필수이고 점수는 없거나 여러 개일 수 있습니다.
첫 번째 값: 문자열
나머지 값: 숫자 배열43. 읽기 전용 튜플
튜플도 `readonly`로 만들 수 있습니다.
const coordinate:
readonly [number, number] = [
37.5665,
126.978,
];요소를 변경하려 하면 오류가 발생합니다.
coordinate[0] = 0;타입 별칭으로 만들 수도 있습니다.
type Coordinate =
readonly [
latitude: number,
longitude: number,
];const seoul: Coordinate = [
37.5665,
126.978,
];좌표, 고정 설정, 함수의 변경되어서는 안 되는 반환값에 유용합니다.
44. `as const`로 읽기 전용 튜플 만들기
다음 배열을 살펴보겠습니다.
const status = [
"success",
200,
];TypeScript는 일반적으로 넓은 배열 타입으로 추론할 수 있습니다.
(string | number)[]`as const`를 사용하면 각 값과 순서를 고정한 읽기 전용 튜플로 추론됩니다.
const status = [
"success",
200,
] as const;추론 타입은 다음과 비슷합니다.
readonly ["success", 200]이제 요소를 수정할 수 없습니다.
status[0] = "error";`as const`는 TypeScript에게 다음과 같이 말합니다.
“이 배열은 임시 목록이 아니라 값과 순서가 고정된 명찰입니다.”
타입 단언은 11편에서 더 자세히 다룰 예정입니다.
45. 구조 분해 할당과 튜플
튜플의 값을 각각의 변수로 꺼낼 때 구조 분해 할당을 사용할 수 있습니다.
const userInfo:
[string, number] = [
"김타입",
25,
];
const [userName, age] =
userInfo;TypeScript는 각 변수의 타입을 정확히 추론합니다.
userName; // string
age; // number출력해 보겠습니다.
console.log(userName);
console.log(age);함수의 반환값을 튜플로 만들 때 특히 유용합니다.
function getUserInfo():
[string, number] {
return [
"김타입",
25,
];
}구조 분해로 받습니다.
const [name, userAge] =
getUserInfo();46. 함수에서 튜플 반환하기
함수가 서로 다른 타입의 값을 여러 개 반환해야 할 때 튜플을 사용할 수 있습니다.
function calculateResult(
score: number
): [boolean, string] {
if (score >= 60) {
return [
true,
"합격입니다.",
];
}
return [
false,
"불합격입니다.",
];
}함수를 호출합니다.
const [isPassed, message] =
calculateResult(85);각 변수의 타입:
isPassed; // boolean
message; // string출력합니다.
console.log(isPassed);
console.log(message);출력 결과:
true
합격입니다.튜플을 사용하면 여러 값을 간결하게 반환할 수 있습니다.
다만 반환되는 값의 개수가 많아지거나 각 값의 의미가 복잡해지면 객체를 사용하는 편이 더 읽기 좋습니다.
47. 튜플과 객체 중 무엇을 사용해야 할까?
다음 튜플을 살펴보겠습니다.
const user:
[number, string, boolean] = [
1,
"김타입",
true,
];각 위치의 의미를 기억해야 합니다.
0번: id
1번: name
2번: isActive요소가 많아지면 읽기 어려워집니다.
객체로 작성하면 의미가 더 명확합니다.
const user = {
id: 1,
name: "김타입",
isActive: true,
};튜플은 다음 상황에 적합합니다.
- 요소 수가 적을 때
- 순서가 명확할 때
- 좌표처럼 관례가 있을 때
- 함수에서 간단한 여러 값을 반환할 때
- 구조 분해 할당으로 바로 사용할 때
객체는 다음 상황에 더 적합합니다.
- 속성이 많을 때
- 각 값의 이름이 중요할 때
- 필드가 추가될 가능성이 있을 때
- 순서보다 의미가 중요할 때
두 개의 값까지만 담긴 작은 여행 가방에는 튜플이 편합니다.
열두 개의 값이 들어가는 이삿짐이라면 상자마다 이름을 적은 객체가 낫습니다.
48. 튜플의 주의점
튜플은 요소 개수를 제한하지만 일부 배열 메서드 사용에서는 예상보다 느슨하게 느껴질 수 있습니다.
const user:
[string, number] = [
"김타입",
25,
];TypeScript 버전과 상황에 따라 `push()` 같은 배열 메서드가 허용되는 것처럼 보일 수 있습니다.
user.push("추가 값");하지만 추가된 요소를 튜플의 정해진 위치 타입으로 안전하게 사용할 수 있는 것은 아닙니다.
튜플의 길이와 구조를 확실히 고정하려면 읽기 전용 튜플을 사용하는 것이 좋습니다.
const user:
readonly [string, number] = [
"김타입",
25,
];이제 `push()`를 사용할 수 없습니다.
user.push("추가 값");튜플을 고정된 구조로 사용한다면 `readonly`를 적극적으로 고려할 수 있습니다.
49. 실습 1: 학생 점수 관리하기
학생 점수 배열을 만들어 보겠습니다.
const scores: number[] = [
95,
80,
55,
100,
70,
];합격 점수만 선택합니다.
const passedScores =
scores.filter(
(score) => score >= 60
);각 점수를 메시지로 바꿉니다.
const scoreMessages =
passedScores.map(
(score) => `${score}점 합격`
);평균 점수를 계산합니다.
const total = scores.reduce(
(sum, score) => sum + score,
0
);
const average =
total / scores.length;결과를 출력합니다.
console.log(
`전체 점수: ${scores}`
);
console.log(
`합격 점수: ${passedScores}`
);
console.log(scoreMessages);
console.log(
`평균 점수: ${average}`
);전체 코드입니다.
const scores: number[] = [
95,
80,
55,
100,
70,
];
const passedScores =
scores.filter(
(score) => score >= 60
);
const scoreMessages =
passedScores.map(
(score) => `${score}점 합격`
);
const total = scores.reduce(
(sum, score) => sum + score,
0
);
const average =
total / scores.length;
console.log(
`전체 점수: ${scores}`
);
console.log(
`합격 점수: ${passedScores}`
);
console.log(scoreMessages);
console.log(
`평균 점수: ${average}`
);50. 실습 2: 상품 목록 필터링하기
상품 타입을 정의합니다.
type Product = {
id: number;
name: string;
price: number;
isSoldOut: boolean;
};상품 배열을 만듭니다.
const products: Product[] = [
{
id: 1,
name: "키보드",
price: 120000,
isSoldOut: false,
},
{
id: 2,
name: "마우스",
price: 60000,
isSoldOut: true,
},
{
id: 3,
name: "모니터",
price: 350000,
isSoldOut: false,
},
];판매 가능한 상품만 선택합니다.
const availableProducts =
products.filter(
(product) => !product.isSoldOut
);상품 이름과 가격을 문자열로 변환합니다.
const productMessages =
availableProducts.map(
(product) =>
`${product.name}: ${product.price}원`
);특정 상품을 찾습니다.
const monitor =
products.find(
(product) =>
product.name === "모니터"
);안전하게 결과를 출력합니다.
const monitorPrice =
monitor?.price ?? 0;
console.log(productMessages);
console.log(
`모니터 가격: ${monitorPrice}원`
);51. 실습 3: 좌표 이동하기
좌표를 튜플로 표현해 보겠습니다.
type Point = readonly [
x: number,
y: number,
];현재 위치를 만듭니다.
const currentPoint: Point = [
10,
20,
];좌표를 이동시키는 함수를 작성합니다.
function movePoint(
point: Point,
moveX: number,
moveY: number
): Point {
return [
point[0] + moveX,
point[1] + moveY,
];
}함수를 호출합니다.
const movedPoint =
movePoint(
currentPoint,
5,
-3
);구조 분해로 좌표를 꺼냅니다.
const [x, y] = movedPoint;
console.log(`x: ${x}`);
console.log(`y: ${y}`);출력 결과:
x: 15
y: 17읽기 전용 튜플을 사용했기 때문에 원래 좌표를 수정하지 않고 새로운 좌표를 반환합니다.
52. 실습 4: 로그인 결과 반환하기
로그인 결과를 튜플로 반환해 보겠습니다.
type LoginResult = readonly [
success: boolean,
message: string,
];로그인 함수를 작성합니다.
function login(
userName: string,
password: string
): LoginResult {
if (
userName === "admin" &&
password === "1234"
) {
return [
true,
"로그인에 성공했습니다.",
];
}
return [
false,
"아이디 또는 비밀번호가 틀렸습니다.",
];
}함수를 호출합니다.
const [success, message] =
login("admin", "1234");결과를 확인합니다.
if (success) {
console.log(`✅ ${message}`);
} else {
console.log(`❌ ${message}`);
}출력 결과:
✅ 로그인에 성공했습니다.두 값으로 이루어진 간단한 결과라면 튜플이 깔끔하게 동작합니다.
결과에 사용자 정보, 토큰, 만료 시간 등 많은 필드가 추가된다면 객체로 전환하는 것이 좋습니다.
53. 자주 발생하는 실수
실수 1. 빈 배열에 타입을 작성하지 않기
const users = [];어떤 값을 저장할 배열인지 명확하지 않습니다.
const users: string[] = [];실수 2. 배열 인덱스가 1부터 시작한다고 생각하기
const languages = [
"JavaScript",
"TypeScript",
];
console.log(languages[1]);첫 번째 요소가 아니라 두 번째 요소인 `"TypeScript"`가 나옵니다.
첫 번째 요소는 다음과 같습니다.
languages[0];실수 3. `find()`가 항상 값을 반환한다고 생각하기
const score =
scores.find(
(score) => score === 1000
);
console.log(score.toFixed(2));값을 찾지 못하면 `undefined`입니다.
if (score !== undefined) {
console.log(score.toFixed(2));
}실수 4. `map()`이 원본 배열을 변경한다고 생각하기
const numbers = [1, 2, 3];
numbers.map(
(number) => number * 2
);
console.log(numbers);결과:
[1, 2, 3]반환된 배열을 변수에 저장해야 합니다.
const doubled =
numbers.map(
(number) => number * 2
);실수 5. 튜플의 순서를 바꾸기
const user:
[string, number] = [
25,
"김타입",
];첫 번째 요소는 문자열이어야 하고 두 번째 요소는 숫자여야 합니다.
const user:
[string, number] = [
"김타입",
25,
];실수 6. 튜플에 너무 많은 정보를 넣기
const user:
[
number,
string,
string,
boolean,
string,
number,
] = [
1,
"김타입",
"type@example.com",
true,
"서울",
25,
];무슨 값이 어느 위치인지 파악하기 어렵습니다.
객체를 사용하는 편이 좋습니다.
const user = {
id: 1,
name: "김타입",
email: "type@example.com",
isActive: true,
city: "서울",
age: 25,
};실수 7. 고정 튜플을 일반 배열처럼 수정하기
const coordinate:
[number, number] = [
10,
20,
];
coordinate.push(30);고정 구조라면 읽기 전용 튜플을 사용합니다.
const coordinate:
readonly [number, number] = [
10,
20,
];54. 배열과 튜플 선택 공식
여러 값을 저장해야 할 때 다음 질문을 확인해 보세요.
질문 1. 같은 종류의 값이 여러 개인가?
배열을 사용합니다.
const scores: number[] = [
90,
80,
100,
];질문 2. 데이터 개수가 계속 달라질 수 있는가?
배열이 적합합니다.
const todoList: string[] = [];질문 3. 각 위치의 의미와 타입이 정해져 있는가?
튜플을 고려합니다.
const coordinate:
[number, number] = [
10,
20,
];질문 4. 값의 개수가 적고 구조 분해로 바로 사용할 것인가?
튜플이 편리할 수 있습니다.
const [success, message] =
login();질문 5. 필드가 많고 각 값의 이름이 중요한가?
객체를 사용하는 것이 좋습니다.
const user = {
id: 1,
name: "김타입",
};질문 6. 배열이나 튜플이 수정되면 안 되는가?
`readonly`를 사용합니다.
readonly number[]readonly [string, number]55. 미니 퀴즈
문제 1
다음 배열의 타입은 무엇일까요?
const scores = [
90,
85,
100,
];정답
number[]모든 요소가 숫자이므로 숫자 배열로 추론됩니다.
문제 2
다음 코드에서 오류가 발생하는 이유는 무엇일까요?
const languages:
string[] = [
"JavaScript",
"TypeScript",
];
languages.push(100);정답
`languages`는 문자열 배열인데 숫자를 추가했기 때문입니다.
문제 3
다음 코드의 출력 결과는 무엇일까요?
const values = [
10,
20,
30,
];
console.log(values[0]);정답
10배열의 첫 번째 요소는 0번 인덱스에 있습니다.
문제 4
다음 코드에서 `found`의 타입은 무엇일까요?
const numbers = [
10,
20,
30,
];
const found =
numbers.find(
(number) => number === 100
);정답
number | undefined값을 찾지 못하면 `undefined`를 반환할 수 있습니다.
문제 5
다음 두 타입은 같은 의미일까요?
number[]
Array<number>정답
네, 둘 다 숫자 배열을 의미합니다.
문제 6
다음 튜플에서 오류가 발생하는 이유는 무엇일까요?
const user:
[string, number] = [
25,
"김타입",
];정답
첫 번째 요소는 문자열, 두 번째 요소는 숫자여야 하는데 순서가 바뀌었습니다.
문제 7
다음 코드에서 `name`과 `age`의 타입은 무엇일까요?
const user:
[string, number] = [
"김타입",
25,
];
const [name, age] = user;정답
name; // string
age; // number문제 8
다음 타입에서 세 번째 요소는 필수일까요?
type UserInfo = [
string,
number,
string?,
];정답
아닙니다.
세 번째 문자열 요소는 선택 사항입니다.
문제 9
다음 코드를 수정하지 못하도록 변경해 보세요.
const coordinate:
[number, number] = [
10,
20,
];정답
const coordinate:
readonly [number, number] = [
10,
20,
];문제 10
학생들의 이름 목록에는 배열과 튜플 중 어떤 타입이 적절할까요?
["김타입", "이컴파일", "박제네릭"]정답
문자열 배열이 적절합니다.
string[]학생 수가 달라질 수 있고 모든 요소가 문자열이기 때문입니다.
56. 핵심 정리
배열
여러 값을 하나의 변수로 관리합니다.
const scores: number[] = [
90,
85,
100,
];배열 타입 작성법
두 문법은 같은 의미입니다.
number[]
Array<number>배열 인덱스는 0부터 시작
const firstScore = scores[0];배열 값 추가와 제거
scores.push(95);
scores.pop();
scores.unshift(70);
scores.shift();배열 변환과 검색
scores.map(
(score) => score * 2
);
scores.filter(
(score) => score >= 60
);
scores.find(
(score) => score === 100
);`find()`는 `undefined`를 반환할 수 있음
const score:
number | undefined =
scores.find(
(score) => score === 100
);읽기 전용 배열
const scores:
readonly number[] = [
90,
85,
];튜플
위치별 타입과 요소 개수가 정해진 배열입니다.
const user:
[string, number] = [
"김타입",
25,
];이름이 붙은 튜플
type UserInfo = [
name: string,
age: number,
];선택적 튜플
type UserInfo = [
name: string,
age: number,
nickname?: string,
];읽기 전용 튜플
const coordinate:
readonly [number, number] = [
10,
20,
];배열과 튜플의 선택
같은 종류의 값이 여러 개
→ 배열
개수와 위치별 타입이 고정
→ 튜플
필드가 많고 이름이 중요함
→ 객체57. 마무리
배열은 여러 값을 한곳에 모아 관리할 수 있게 해주는 자료구조입니다.
const languages: string[] = [
"JavaScript",
"TypeScript",
"Python",
];값을 추가하고 제거할 수 있으며, 필요한 값을 찾거나 새로운 배열로 변환할 수도 있습니다.
languages.push("Java");
const longNames =
languages.filter(
(language) =>
language.length >= 6
);
const upperNames =
languages.map(
(language) =>
language.toUpperCase()
);튜플은 배열보다 조금 더 엄격합니다.
const user:
[string, number] = [
"김타입",
25,
];요소의 개수와 위치별 타입이 정해져 있기 때문에 좌표나 간단한 함수 결과처럼 순서가 중요한 데이터에 적합합니다.
핵심은 다음과 같습니다.
배열은 목록을 관리한다.
튜플은 구조를 관리한다.배열은 같은 종류의 승객들이 자유롭게 타는 버스입니다.
튜플은 각 좌석에 승객 타입이 적힌 예약 열차입니다.
어떤 교통수단을 선택할지는 데이터가 얼마나 많고, 순서가 얼마나 중요한지에 달려 있습니다. 🚌🚆
58. 다음 편 예고
지금까지 우리는 배열에 같은 종류의 값을 여러 개 저장하고, 튜플에 위치별로 서로 다른 타입을 저장하는 방법을 알아봤습니다.
const scores: number[] = [
90,
85,
100,
];
const user:
[string, number] = [
"김타입",
25,
];그런데 하나의 변수에 문자열 또는 숫자 중 하나가 들어올 수 있다면 어떻게 해야 할까요?
let userId: string | number;사용자 ID가 숫자일 수도 있고 문자열일 수도 있는 프로그램은 실제로 자주 등장합니다.
버튼의 상태를 아무 문자열로나 허용하지 않고 특정 값만 허용하고 싶을 수도 있습니다.
let buttonStatus:
"idle" | "loading" | "success";`buttonStatus`에는 세 문자열 중 하나만 저장할 수 있습니다.
buttonStatus = "loading";하지만 목록에 없는 값은 저장할 수 없습니다.
buttonStatus = "running";여러 타입 중 하나를 허용하는 유니언 타입과, 특정 값 자체를 타입으로 사용하는 리터럴 타입은 TypeScript의 표현력을 크게 높여줍니다.
그렇다면 `string | number` 타입의 값은 어떻게 안전하게 사용할까요?
function printId(
id: string | number
) {
// 문자열일까요?
// 숫자일까요?
}다음 편에서는 하나의 변수에 여러 가능성을 담되, 아무 값이나 들어오지는 못하게 만드는 TypeScript의 정교한 타입 조합을 살펴보겠습니다.
다음 이야기
[TypeScript 완전정복 #9] 하나의 변수에 여러 타입을 담는 방법 | 유니언 타입과 리터럴 타입 완벽 이해하기
- 유니언 타입은 무엇일까요?
- `string | number`는 어떻게 사용할까요?
- 유니언 타입의 값은 왜 바로 사용할 수 없을까요?
- `typeof`로 타입을 안전하게 구분하려면 어떻게 해야 할까요?
- 리터럴 타입은 일반 타입과 무엇이 다를까요?
- 특정 문자열과 숫자만 허용하려면 어떻게 해야 할까요?
- 유니언 타입과 리터럴 타입을 함께 사용하면 무엇이 좋아질까요?
- 상태값과 옵션을 타입으로 제한하려면 어떻게 해야 할까요?
다음 편에서는 여러 가능성을 허용하면서도 코드의 출입문은 단단히 지키는 유니언 타입과 리터럴 타입을 만나보겠습니다.
