TYPESCRIPT · 심층 가이드
TypeScript 컬렉션 완전 정리
map과 filter, reduce는 JavaScript와 같은 메서드지만 TypeScript에서는 누적자 타입과 요소 타입이 어디서 좁혀지고 어디서 넓어지는지가 코드의 안전성을 결정합니다.
TypeScript의 컬렉션 작업에는 런타임 동작과 타입 추론이라는 두 층이 겹쳐 있습니다. 런타임에서는 그냥 배열 메서드지만, 컴파일러는 콜백의 반환값을 보고 결과 타입을 새로 만들어 냅니다. 초심자의 모델이 깨지는 지점은 대개 reduce입니다. 초기값으로 넘긴 []가 never[]로 추론되어 첫 push부터 에러가 나거나, 반대로 제네릭 인자를 명시하는 순간 콜백 안의 실수를 컴파일러가 더 이상 잡아 주지 못합니다.
앞쪽 map 변환과 filter 필터링은 배열의 길이와 요소 타입 중 무엇이 바뀌는지를 나누어 보는 연습입니다. reduce 합계에서 누적자라는 개념이 등장하고, 이 누적자를 객체로 바꾸면 곧바로 groupBy 구현과 빈도표 만들기가 됩니다. Set 중복 제거부터는 자료구조 선택 문제로 넘어가며, chunk 나누기와 sliding window는 같은 인덱스 계산을 다른 각도로 반복해 감을 굳히는 구간입니다.
덜 알려진 함정은 filter가 타입을 좁혀 주지 않는다는 점입니다. arr.filter(x => x !== undefined)를 써도 결과는 여전히 (T | undefined)[]이고, 뒤에서 !를 붙이는 습관으로 이어집니다. 콜백을 x is T 형태의 타입 서술어로 선언해야 컴파일러가 결과를 T[]로 인정합니다. 객체를 키로 쓰는 Set과 Map이 값이 아니라 참조로 비교한다는 점도 중복 제거에서 자주 발목을 잡습니다.
01map 변환
TypeScript에서 map 변환 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// map 변환
const items: number[] = [1, 2, 3, 1];
console.log(items.map(value => value * 2));컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
02filter 필터링
TypeScript에서 filter 필터링 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// filter 필터링
const words: string[] = ["js", "ts", "js", "rust"];
console.log([...new Set(words)]);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
03reduce 합계
TypeScript에서 reduce 합계 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// reduce 합계
const rows = [{ team: "a", score: 2 }, { team: "b", score: 3 }, { team: "a", score: 3 }];
const grouped = rows.reduce((acc, row) => { (acc[row.team] ??= []).push(row.score); return acc; }, {});
console.log(grouped);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
04첫 요소 찾기
TypeScript에서 첫 요소 찾기 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// 첫 요소 찾기
const values: number[] = [1, 2, 3, 4, 5];
const chunks = [];
for (let i = 0; i < values.length; i += 2) chunks.push(values.slice(i, i + 2));
console.log(chunks);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
05Set 중복 제거
TypeScript에서 Set 중복 제거 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// Set 중복 제거
const items: number[] = [1, 2, 3, 5];
console.log(items.map(value => value * 2));컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
06단어 수 세기
TypeScript에서 단어 수 세기 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// 단어 수 세기
const words: string[] = ["js", "ts", "js", "rust"];
console.log([...new Set(words)]);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
07스택 구현
TypeScript에서 스택 구현 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// 스택 구현
const rows = [{ team: "a", score: 2 }, { team: "b", score: 3 }, { team: "a", score: 7 }];
const grouped = rows.reduce((acc, row) => { (acc[row.team] ??= []).push(row.score); return acc; }, {});
console.log(grouped);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
08큐 구현
TypeScript에서 큐 구현 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// 큐 구현
const values: number[] = [1, 2, 3, 4, 5];
const chunks = [];
for (let i = 0; i < values.length; i += 2) chunks.push(values.slice(i, i + 2));
console.log(chunks);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
092차원 배열 합계
TypeScript에서 2차원 배열 합계 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// 2차원 배열 합계
const items: number[] = [1, 2, 3, 9];
console.log(items.map(value => value * 2));컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
10groupBy 구현
TypeScript에서 groupBy 구현 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// groupBy 구현
const words: string[] = ["js", "ts", "js", "rust"];
console.log([...new Set(words)]);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
11flatten 펼치기
TypeScript에서 flatten 펼치기 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// flatten 펼치기
const rows = [{ team: "a", score: 2 }, { team: "b", score: 3 }, { team: "a", score: 11 }];
const grouped = rows.reduce((acc, row) => { (acc[row.team] ??= []).push(row.score); return acc; }, {});
console.log(grouped);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
12zip 묶기
TypeScript에서 zip 묶기 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// zip 묶기
const values: number[] = [1, 2, 3, 4, 5];
const chunks = [];
for (let i = 0; i < values.length; i += 2) chunks.push(values.slice(i, i + 2));
console.log(chunks);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
13chunk 나누기
TypeScript에서 chunk 나누기 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// chunk 나누기
const items: number[] = [1, 2, 3, 13];
console.log(items.map(value => value * 2));컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
14key 기준 정렬
TypeScript에서 key 기준 정렬 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// key 기준 정렬
const words: string[] = ["js", "ts", "js", "rust"];
console.log([...new Set(words)]);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
15빈도표 만들기
TypeScript에서 빈도표 만들기 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// 빈도표 만들기
const rows = [{ team: "a", score: 2 }, { team: "b", score: 3 }, { team: "a", score: 15 }];
const grouped = rows.reduce((acc, row) => { (acc[row.team] ??= []).push(row.score); return acc; }, {});
console.log(grouped);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
16대소문자 무시 중복 제거
TypeScript에서 대소문자 무시 중복 제거 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// 대소문자 무시 중복 제거
const values: number[] = [1, 2, 3, 4, 5];
const chunks = [];
for (let i = 0; i < values.length; i += 2) chunks.push(values.slice(i, i + 2));
console.log(chunks);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
17sliding window
TypeScript에서 sliding window 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// sliding window
const items: number[] = [1, 2, 3, 17];
console.log(items.map(value => value * 2));컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
18pair 목록을 맵으로 변환
TypeScript에서 pair 목록을 맵으로 변환 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// pair 목록을 맵으로 변환
const words: string[] = ["js", "ts", "js", "rust"];
console.log([...new Set(words)]);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
19reverse 복사
TypeScript에서 reverse 복사 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// reverse 복사
const rows = [{ team: "a", score: 2 }, { team: "b", score: 3 }, { team: "a", score: 19 }];
const grouped = rows.reduce((acc, row) => { (acc[row.team] ??= []).push(row.score); return acc; }, {});
console.log(grouped);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
20partition 나누기
TypeScript에서 partition 나누기 개념을 코드로 빠르게 확인하는 컬렉션 예제입니다.
TypeScript code
// partition 나누기
const values: number[] = [1, 2, 3, 4, 5];
const chunks = [];
for (let i = 0; i < values.length; i += 2) chunks.push(values.slice(i, i + 2));
console.log(chunks);컬렉션 연산은 원본을 바꾸는지 새 값을 만드는지 꼭 함께 확인하세요.
정렬, 필터, 추가 연산이 원본을 바꾸는지 혼동하면 버그로 이어지기 쉽습니다.
정리하며
reduce의 초기값이 누적자 타입을 정하므로 빈 배열·빈 객체에는 타입을 명시합니다.filter로null을 걸러도 타입은 그대로이니x is T서술어를 씁니다.Set과Map은 객체를 참조로 비교하므로 중복 제거 전에 키 문자열을 만듭니다.sort는 원본을 바꾸므로 정렬 전에 스프레드로 복사본을 먼저 만듭니다.
더 깊이 들어가고 싶다면 TypeScript 학습 라이브러리에서 다른 주제 가이드를 이어서 보거나, 언어 비교에서 같은 개념이 다른 언어에서 어떻게 표현되는지 확인해 보세요.