타입 가드
1. 타입 가드
타입 가드를 사용하면 특정 스코프 내에서 타입을 보장할 수 있습니다. "이 객체가 특정 타입인지 확인하고, 맞다면 TypeScript에게 그 사실을 알려주는" 방법이라고 생각하시면 됩니다.
1.1 typeof 타입 가드
typeof는 JavaScript의 typeof처럼 Array를 Object로 반환합니다. 따라서 객체를 취급할 때에는 주의해야 합니다.
function processValue(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase(); // string으로 타입 보장
}
return value.toFixed(2); // number로 타입 보장
}
function processValue(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase(); // string으로 타입 보장
}
return value.toFixed(2); // number로 타입 보장
}
typeof는 javascript와 typescript모두 연산이 정확하지 않기 때문에 아래와 같이 별도의 사용자 정의 함수를 만들어 사용하는 것을 권합니다. javascript에서 사용 가능한 코드입니다.
function typeCheck(value) {
const return_value = Object.prototype.toString.call(value);
const type = return_value.substring(
return_value.indexOf(" ") + 1,
return_value.indexOf("]")
);
return type.toLowerCase();
}
function typeCheck(value) {
const return_value = Object.prototype.toString.call(value);
const type = return_value.substring(
return_value.indexOf(" ") + 1,
return_value.indexOf("]")
);
return type.toLowerCase();
}
타입스크립트에서는 아래와 같이 사용할 수 있습니다.
function typeCheck(value: any): string {
const return_value = Object.prototype.toString.call(value);
const type = return_value.substring(
return_value.indexOf(" ") + 1,
return_value.indexOf("]")
);
return type.toLowerCase();
}
console.log(typeCheck([]));
console.log(typeCheck(null));
function typeCheck(value: any): string {
const return_value = Object.prototype.toString.call(value);
const type = return_value.substring(
return_value.indexOf(" ") + 1,
return_value.indexOf("]")
);
return type.toLowerCase();
}
console.log(typeCheck([]));
console.log(typeCheck(null));
1.2 instanceof 타입 가드
class Dog {
bark() { return "Woof!"; }
}
class Cat {
meow() { return "Meow!"; }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
return animal.bark();
}
return animal.meow();
}
const dog = new Dog();
const cat = new Cat();
console.log(makeSound(dog)); // Woof!
console.log(makeSound(cat)); // Meow!
class Dog {
bark() { return "Woof!"; }
}
class Cat {
meow() { return "Meow!"; }
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
return animal.bark();
}
return animal.meow();
}
const dog = new Dog();
const cat = new Cat();
console.log(makeSound(dog)); // Woof!
console.log(makeSound(cat)); // Meow!
1.3 사용자 정의 타입 가드
interface Fish {
swim(): void;
}
interface Bird {
fly(): void;
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
function move(pet: Fish | Bird) {
if (isFish(pet)) {
pet.swim();
} else {
pet.fly();
}
}
const fish = {
swim: () => console.log("물고기가 헤엄칩니다.")
};
const bird = {
fly: () => console.log("새가 날아갑니다.")
};
move(fish); // "물고기가 헤엄칩니다 🐠"
move(bird); // "새가 날아갑니다 🐦"
interface Fish {
swim(): void;
}
interface Bird {
fly(): void;
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
function move(pet: Fish | Bird) {
if (isFish(pet)) {
pet.swim();
} else {
pet.fly();
}
}
const fish = {
swim: () => console.log("물고기가 헤엄칩니다.")
};
const bird = {
fly: () => console.log("새가 날아갑니다.")
};
move(fish); // "물고기가 헤엄칩니다 🐠"
move(bird); // "새가 날아갑니다 🐦"
pet is Fish
는 TypeScript의 타입 술어(Type Predicate)로, 함수가 true를 반환할 때 해당 매개변수가 Fish 타입이라는 것을 TypeScript에게 알려주는 역할을 합니다. 쉽게 말해서, 이 조건이 참이면 pet은 Fish 타입이다
라고 TypeScript의 타입 시스템에게 알려주는 것입니다.
(pet as Fish).swim !== undefined
는 타입 단언(Type Assertion)을 사용한 코드입니다. pet 객체를 Fish 타입이라고 가정(타입 단언)하고, swim이라는 메서드가 존재하는지 확인합니다. 만약 swim 메서드가 존재한다면 true를 반환하여 이 객체가 Fish 타입이라고 판단합니다. 즉, "물고기라면 반드시 가지고 있어야 할 swim 메서드가 있는지 확인"하는 것입니다.
2. 연습문제
- 다음과 같이 문자열 또는 숫자를 받아서 해당 값의 길이를 반환하는 함수를 작성하세요.
- 문자열이 들어오면 문자열의 길이를 반환
- 숫자가 들어오면 숫자를 문자열로 변환한 후 그 길이를 반환
- 다음과 같이 두 가지 타입의 동물 객체가 있습니다. 각 동물의 특성에 맞게 소리를 출력하는 함수를 작성하세요.
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
bark() {
return "멍멍!";
}
}
class Cat {
name: string;
constructor(name: string) {
this.name = name;
}
meow() {
return "야옹!";
}
}
// 여기에 makeSound 함수를 작성하세요.
// Dog나 Cat을 받아서 각각 알맞은 소리를 반환해야 합니다.
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
bark() {
return "멍멍!";
}
}
class Cat {
name: string;
constructor(name: string) {
this.name = name;
}
meow() {
return "야옹!";
}
}
// 여기에 makeSound 함수를 작성하세요.
// Dog나 Cat을 받아서 각각 알맞은 소리를 반환해야 합니다.
- 다음 코드에 타입 가드를 추가해보세요.
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
// 도형의 면적을 계산하는 함수를 작성하세요.
function calculateArea(shape: Shape): number {
// 여기에 구현
}
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
// 도형의 면적을 계산하는 함수를 작성하세요.
function calculateArea(shape: Shape): number {
// 여기에 구현
}
3. 연습문제 정답
- 문자열 또는 숫자를 받아서 해당 값의 길이를 반환하는 함수
function getLength(value: string | number): number {
if (typeof value === "string") {
return value.length;
}
return String(value).length;
}
// 사용 예시
console.log(getLength("hello")); // 5
console.log(getLength(12345)); // 5
function getLength(value: string | number): number {
if (typeof value === "string") {
return value.length;
}
return String(value).length;
}
// 사용 예시
console.log(getLength("hello")); // 5
console.log(getLength(12345)); // 5
- 각 동물의 특성에 맞게 소리를 출력하는 함수
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
bark() {
return "멍멍!";
}
}
class Cat {
name: string;
constructor(name: string) {
this.name = name;
}
meow() {
return "야옹!";
}
}
function makeSound(animal: Dog | Cat): string {
if (animal instanceof Dog) {
return `${animal.name}이(가) ${animal.bark()}`;
}
return `${animal.name}이(가) ${animal.meow()}`;
}
// 사용 예시
const dog = new Dog("멍멍이");
const cat = new Cat("야옹이");
console.log(makeSound(dog)); // "멍멍이가 멍멍!"
console.log(makeSound(cat)); // "야옹이가 야옹!"
class Dog {
name: string;
constructor(name: string) {
this.name = name;
}
bark() {
return "멍멍!";
}
}
class Cat {
name: string;
constructor(name: string) {
this.name = name;
}
meow() {
return "야옹!";
}
}
function makeSound(animal: Dog | Cat): string {
if (animal instanceof Dog) {
return `${animal.name}이(가) ${animal.bark()}`;
}
return `${animal.name}이(가) ${animal.meow()}`;
}
// 사용 예시
const dog = new Dog("멍멍이");
const cat = new Cat("야옹이");
console.log(makeSound(dog)); // "멍멍이가 멍멍!"
console.log(makeSound(cat)); // "야옹이가 야옹!"
- 도형의 면적을 계산하는 함수 (타입 가드 사용)
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
// 타입 가드 함수들
function isSquare(shape: Shape): shape is Square {
return shape.kind === "square";
}
function isRectangle(shape: Shape): shape is Rectangle {
return shape.kind === "rectangle";
}
function isCircle(shape: Shape): shape is Circle {
return shape.kind === "circle";
}
function calculateArea(shape: Shape): number {
if (isSquare(shape)) {
return shape.size * shape.size;
}
if (isRectangle(shape)) {
return shape.width * shape.height;
}
if (isCircle(shape)) {
return Math.PI * shape.radius * shape.radius;
}
// 모든 케이스를 처리했지만, TypeScript의 타입 체크를 위해 필요
const unreachable: never = shape;
throw new Error(`Unhandled shape type: ${unreachable}`);
}
// 사용 예시
const square: Square = { kind: "square", size: 5 };
const rectangle: Rectangle = { kind: "rectangle", width: 4, height: 6 };
const circle: Circle = { kind: "circle", radius: 3 };
console.log(calculateArea(square)); // 25
console.log(calculateArea(rectangle)); // 24
console.log(calculateArea(circle)); // 약 28.27
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
// 타입 가드 함수들
function isSquare(shape: Shape): shape is Square {
return shape.kind === "square";
}
function isRectangle(shape: Shape): shape is Rectangle {
return shape.kind === "rectangle";
}
function isCircle(shape: Shape): shape is Circle {
return shape.kind === "circle";
}
function calculateArea(shape: Shape): number {
if (isSquare(shape)) {
return shape.size * shape.size;
}
if (isRectangle(shape)) {
return shape.width * shape.height;
}
if (isCircle(shape)) {
return Math.PI * shape.radius * shape.radius;
}
// 모든 케이스를 처리했지만, TypeScript의 타입 체크를 위해 필요
const unreachable: never = shape;
throw new Error(`Unhandled shape type: ${unreachable}`);
}
// 사용 예시
const square: Square = { kind: "square", size: 5 };
const rectangle: Rectangle = { kind: "rectangle", width: 4, height: 6 };
const circle: Circle = { kind: "circle", radius: 3 };
console.log(calculateArea(square)); // 25
console.log(calculateArea(rectangle)); // 24
console.log(calculateArea(circle)); // 약 28.27