TS 2.5 · 2부. 함수와 객체

타입 좁히기

여러 가지일 수 있는 값을 확인해서 하나로 좁힙니다.

예상 학습 시간 16분 실행 단추가 있는 예제는 고쳐서 실행해 볼 수 있습니다 난이도 중급
개념 설명

확인하면 그만큼 좁아집니다

1.4 에서 유니온을 받으면 모두가 가진 것만 사용할 수 있다는 것을 보았습니다. 그러면 어느 쪽인지 확인하면 됩니다.

TypeScript 는 확인하는 코드를 읽고 그 안쪽에서 타입을 좁힙니다. 따로 알려 주지 않아도 if 를 보고 알아냅니다.

if (typeof value === "string") {
	// 여기서 value 는 string 입니다
} else {
	// 여기서는 나머지입니다
}
최소 예제 · 편집 가능

typeof 로 좁히기

main.ts
function show(value: string | number): string {
	if (typeof value === "string") return value.toUpperCase();
	return value.toFixed(1);
}

console.log(show("a-1"));
console.log(show(3));
출력
A-1 3.0

return 뒤에는 else 를 적지 않았는데도 value.toFixed 가 됩니다. 글자인 경우는 이미 돌아갔으니 남은 것은 숫자뿐이라는 것을 압니다.

상세 사용법

값으로 갈라지는 유니온

리터럴 유니온(1.4)은 값을 견주어 좁힙니다. switch 와 잘 맞습니다.

main.ts
type Status = "pending" | "done" | "failed";

function label(status: Status): string {
	switch (status) {
		case "pending": return "기다리는 중";
		case "done": return "끝났습니다";
		case "failed": return "실패했습니다";
	}
}

console.log(label("pending"));
console.log(label("failed"));
출력
기다리는 중 실패했습니다

default 가 없는데도 오류가 나지 않았습니다. 세 가지를 모두 다뤘으니 빠진 경우가 없다는 것을 압니다. 그래서 Status 에 값을 하나 더하면 이 함수가 곧바로 오류가 되어, 고칠 자리를 알려 줍니다.

상세 사용법

객체를 갈라내는 표시

객체가 여러 모양일 때는 모양마다 다른 값을 담는 속성을 하나 두고 그것으로 갈라냅니다. 자주 kindtype 이라고 이름 붙입니다.

main.ts
type Circle = { kind: "circle"; radius: number };
type Rect = { kind: "rect"; width: number; height: number };

function area(shape: Circle | Rect): number {
	if (shape.kind === "circle") return Math.round(shape.radius * shape.radius * 3.14);
	return shape.width * shape.height;
}

console.log(area({ kind: "circle", radius: 10 }));
console.log(area({ kind: "rect", width: 3, height: 4 }));
출력
314 12

shape.kind 를 견주는 것만으로 radiuswidth 를 각각 사용할 수 있게 됩니다. 서버가 돌려주는 응답이 경우마다 다를 때 이 방식을 자주 사용합니다.

main.ts
type Circle = { kind: "circle"; radius: number };
type Rect = { kind: "rect"; width: number; height: number };

function area(shape: Circle | Rect): number {
	return shape.width * shape.height;
}
출력
5:15 TS2339 'Circle | Rect' 형식에 'width' 속성이 없습니다. 'Circle' 형식에 'width' 속성이 없습니다. 5:29 TS2339 'Circle | Rect' 형식에 'height' 속성이 없습니다. 'Circle' 형식에 'height' 속성이 없습니다.

좁히지 않으면 이렇게 막힙니다. 딸린 설명이 왜 없는지 짚어 줍니다 — Circlewidth 가 없기 때문입니다.

흔한 실수

처음에 자주 걸리는 것

typeof null 은 "object" 입니다

JavaScript 의 오래된 규칙이 그대로 있습니다(JS 1.4). typeof x === "object" 로 좁힐 때는 x !== null 을 함께 확인해야 합니다.

배열은 typeof 로 갈라지지 않습니다

배열도 "object" 입니다. Array.isArray(x) 를 사용합니다 — 이것도 좁혀 줍니다.

함수로 빼면 좁힌 것이 풀립니다

if (isString(value)) 처럼 직접 만든 함수로 확인하면 그 안쪽에서 좁혀지지 않습니다. 좁혀 주게 하려면 반환 타입을 value is string 으로 적어야 합니다.

실습 문제

직접 해보기

1. 세 가지 값 설명하기 난이도 중

글자·숫자·참거짓을 받아 각각 다르게 설명하는 함수를 만드세요.

function describe(value: string | number | boolean): string {
	if (typeof value === "string") return `글자 ${value}`;
	if (typeof value === "number") return `숫자 ${value}`;
	return `참거짓 ${value}`;
}

console.log(describe("홍길동"));
console.log(describe(27));
console.log(describe(true));
2. 모양을 하나 더하기 난이도 상

area 에 삼각형을 더하고, 더하는 순간 어디가 오류로 잡히는지 확인하세요.

type Triangle = { kind: "triangle"; base: number; height: number } 를 만들고 매개 변수 타입에 이어 붙입니다. 마지막 return shape.width * shape.height 가 곧바로 막히므로 고쳐야 할 자리를 컴파일러가 알려 줍니다. 이것이 갈라내는 표시를 두는 값입니다.
요약

이 단원의 정리

  • 확인하는 코드를 읽고 그 안쪽에서 타입이 좁아집니다.
  • typeof 로 기본 타입을 갈라냅니다.
  • 리터럴 유니온은 값을 견주어 갈라냅니다.
  • 객체는 갈라내는 표시 속성을 하나 두고 그것으로 갈라냅니다.
  • 모든 경우를 다루면 default 가 없어도 됩니다.