숏컷 코드
const point: [number, number] = [10, 20];
const tags: readonly string[] = ["ts", "types"];배열과 튜플
튜플/readonly 배열에서 먼저 보는 기본형은 아래입니다.
- 고정 길이 튜플:
[number, number] - optional 요소가 있는 튜플:
[string, number?] - rest 요소가 있는 튜플:
[string, ...number[]] - 읽기 전용 배열:
readonly string[]
1) 자리 의미가 고정되면 튜플
튜플은 같은 타입 원소 목록이 아니라, 각 인덱스가 서로 다른 의미를 갖는 짧은 구조를 표현할 때 씁니다.
const result: [boolean, string] = [true, "ok"];이 경우 첫 칸은 성공 여부, 둘째 칸은 메시지라는 계약이 타입에 남습니다.
2) 같은 종류 값 여러 개면 일반 배열
원소가 모두 같은 역할을 하고, 길이도 자연스럽게 늘어날 수 있다면 배열이 더 맞습니다. 즉 튜플은 "목록"보다 "구조화된 한 묶음"에 가깝습니다.
3) 입력을 수정하지 않을 계약이면 readonly T[]
함수 안에서 배열을 읽기만 해야 한다면 readonly 배열로 받는 편이 더 정직합니다.
function printAll(values: readonly string[]) {
return values.join(", ");
}이 표기는 "이 함수는 호출자가 넘긴 배열을 바꾸지 않는다"는 API 계약을 보여 줍니다.
type Command = [name: string, ...args: string[]];
type Response = [ok: boolean, message?: string];4) readonly는 깊은 불변성 전체를 보장하지는 않는다
readonly string[]는 배열 자체 변경만 막고, 원소가 객체라면 그 객체 내부 필드까지 자동으로 고정하지는 않습니다.
const users: readonly { name: string }[] = [{ name: "Mina" }];
users[0].name = "Jin";즉 여기서 핵심은 깊은 불변성 전체보다, 컬렉션 입력 계약을 어디까지 타입에 남길지입니다.
5) 튜플은 구조 분해와 함께 읽는 편이 좋다
튜플의 장점은 각 자리 의미가 분명하다는 점이므로, 인덱스로 접근하기보다 구조 분해로 의미를 드러내는 쪽이 더 읽기 쉽습니다.
언제 튜플로 고정할까
- 자리 의미가 고정된 짧은 구조다: 튜플
- 같은 타입 원소 목록이다: 배열
- 함수가 입력 배열을 수정하지 않는다:
readonly T[] - 깊은 불변성이 필요하다: 별도 전략 검토
- 튜플을 쓴다: 구조 분해로 의미를 드러냄
주의할 점
튜플을 일반 배열처럼 느슨하게 다루면 각 자리 의미를 잃기 쉽습니다.
// ❌ 각 인덱스 의미를 모호하게 만듦
const result: [boolean, string] = [true, "ok"];
const value = result[1];
// ✅ 구조 분해로 의미를 드러냄
const [ok, message] = result;참고 링크
1 sources