TypeScript - 타입 호환성

안녕하세요, 미래의 코딩 마법사 여러분! 오늘 우리는 TypeScript의 세계로 흥미로운 여정을 떠나 타입 호환성에 대해 탐구해보겠습니다. 프로그래밍에 새로운 사람이라면 걱정 마세요 - 저는 친절한 안내자가 되어 이 주제를 단계별로 풀어나갈 것입니다. 그러니 가상의魔杖(키보드)을 손에 들고 TypeScript의 마법을 쓰러가요!

TypeScript - Type Compatibility

TypeScript는 어떻게 타입 호환성을 확인 하나요?

다양한 모양의 블록을 구멍에 맞추려고 할 때를 상상해보세요. TypeScript의 타입 호환성은 이와 비슷합니다 - 하나의 타입이 다른 타입에 맞는지 여부입니다. 하지만 물리적인 모양이 아니라 데이터 타입을 다루고 있습니다.

구조적 타입 지정

TypeScript는 우리가 "구조적 타입 지정"이라고 부르는 방식을 사용합니다. 이는 그저 객체의 정확한 타입 이름보다는 객체의 형태에 더 주의를 기울인다는 뜻입니다. 예를 보겠습니다:

interface Pet {
name: string;
}

class Dog {
name: string;
}

let pet: Pet;
let dog = new Dog();

pet = dog; // 이건 괜찮아요!

이 마법의 동물원에서 TypeScript는 "와, PetDog 모두 name 프로퍼티가 문자열 타입을 가지고 있어. 둘 모두 같게 보여, 그래서 호환됩니다!"라고 말합니다. 마치 정사각형 망치가 정사각형 구멍에 맞는다고 말하는 것과 같습니다.

덕 타입 지정

프로그래밍에 재미있는 말이 있습니다: "만약 그것이 오리처럼 걸어다니고 오리처럼 꽥꽥거린다면, 그것은 반드시 오리입니다." 이것이 덕 타입 지정의 본質입니다. TypeScript는 이 철학을 수용합니다. 그것을 실제로 보겠습니다:

interface Quacker {
quack(): void;
}

class Duck {
quack() {
console.log("Quack!");
}
}

class Person {
quack() {
console.log("오리를 흉내내고 있어요!");
}
}

let quacker: Quacker = new Duck(); // 분명히 괜찮아요
quacker = new Person(); // 이것도 괜찮아요!

TypeScript는 Person이 명시적으로 Quacker로 선언되지 않았다고 신경 쓰지 않습니다. PersonQuacker와 같은 quack 메서드를 가지고 있다면 충분합니다. 따라서 DuckPerson 모두 Quacker와 호환됩니다.

타입 호환성을 효과적으로 사용하는 방법

타입 호환성을 효과적으로 사용하는 것은 마법의 퍼즐을 풀는 것과 같습니다. 다음은 몇 가지 팁입니다:

1. 객체 리터럴 확인 이해하기

TypeScript는 객체 리터럴에 더 엄격합니다. 왜 그런지 보겠습니다:

interface Point {
x: number;
y: number;
}

let p: Point;

// 이건 괜찮아요
p = { x: 10, y: 20 };

// 이것은 오류를 일으킬 것입니다
p = { x: 10, y: 20, z: 30 };

TypeScript는 "와, 나는 Point를 요청했지만, 너는 추가적인 것(z)을 주고 있어. 그거는 안 돼!"라고 말합니다. 이는 객체를 잘못 사용할 수 있는 잠재적 버그를 찾는 데 도움이 됩니다.

2. 선택적 프로퍼티 사용하기

occasionally. 이를 위해 선택적 프로퍼티를 사용할 수 있습니다:

interface Options {
color?: string;
width?: number;
}

function configure(options: Options) {
// ...
}

configure({ color: "red" }); // 괜찮아요
configure({ width: 100 }); // 괜찮아요
configure({}); // 이것도 괜찮아요!

프로퍼티를 선택적으로 만들어 두면 TypeScript에게 "이 프로퍼티가 항상 존재하지 않아도 괜찮다"고 말하고 있습니다.

함수와 타입 호환성

함수는 프로그래밍의 스위스 아ーノ이 knife와 같습니다 - 매우 다用途적입니다. 함수와 타입 호환성이 어떻게 작동하는지 보겠습니다:

매개변수 호환성

TypeScript는 함수 매개변수에 대해 상당히 관대합니다:

let x = (a: number) => 0;
let y = (b: number, s: string) => 0;

y = x; // 괜찮아요
x = y; // 오류

이는 반대直觉적일 수 있지만 안전합니다. TypeScript는 "만약 당신이 두 개의 매개변수를 기대하는 함수를 주었다면, 더 적은 매개변수를 가진 함수를 주는 것은 괜찮다. 추가 매개변수는 무시될 것입니다."라고 말합니다.

반환 타입 호환성

반환 타입도 호환되어야 합니다:

let x = () => ({name: "Alice"});
let y = () => ({name: "Alice", location: "원더랜드"});

x = y; // 괜찮아요
y = x; // 오류

기대보다 더 많이 반환하는 것은 괜찮지만, 적게 반환하는 것은 안 됩니다. 마치 토피링이 추가된 피자를 주문하고 무료로 추가 토피링을 받는 것이 좋지만, 토피링이 추가된 피자를 주문하고 단지 도우를 받는 것이 실망스러운 것과 같습니다.

클래스와 타입 호환성

클래스는 객체의 블루프린트와 같고, 비슷한 호환성 규칙을 따릅니다:

class Animal {
feet: number;
constructor(name: string, numFeet: number) { }
}

class Size {
feet: number;
}

let a: Animal;
let s: Size;

a = s; // 괜찮아요
s = a; // 괜찮아요

TypeScript는 인스턴스 멤버에 대해 신경 쓰지 않습니다. "둘 모두 feet 프로퍼티를 가지고 있니? 충분하다!"라고 말합니다.

private과 protected 멤버

하지만 클래스에 private이나 protected 멤버가 있을 때, 사정이 더 엄격해집니다:

class Animal {
private name: string;
constructor(theName: string) { this.name = theName; }
}

class Rhino extends Animal {
constructor() { super("Rhino"); }
}

class Employee {
private name: string;
constructor(theName: string) { this.name = theName; }
}

let animal = new Animal("Goat");
let rhino = new Rhino();
let employee = new Employee("Bob");

animal = rhino; // 괜찮아요
animal = employee; // 오류: 'Animal'과 'Employee'는 호환되지 않습니다

AnimalEmployee가 같아 보이지만, TypeScript는 그들의 private 멤버가 다른 선언에서 오는 것으로 간주합니다.

결론

이제 TypeScript의 타입 호환성에 대한 여정이 끝났습니다. 친절한 마법사가 어깨에 기대어 코드를 작성할 때 실수를 조금씩 잡아주는 것처럼, TypeScript는 더 나은, 안전한 코드를 작성하는 데 도와줍니다.

계속 연습하고, 실험하고, 곧 TypeScript의 마법을 마스터하면 됩니다! 다음 번에 다시 만나요, 행복한 코딩을 기원합니다!

방법 설명
구조적 타입 지정 타입의 구조를 기반으로 호환성을 확인
덕 타입 지정 필요한 프로퍼티/메서드가 있으면 호환됨
객체 리터럴 확인 잠재적 버그를 찾기 위해 엄격한 확인
선택적 프로퍼티 프로퍼티가 항상 존재하지 않아도 괜찮음
매개변수 호환성 fewer parameters can be assigned to those with more
반환 타입 호환성 Functions can return more than expected, but not less
클래스 호환성 인스턴스 멤버 기반으로 호환성 확인
private/protected 멤버 클래스의 private/protected 멤버는 자식 클래스와 호환됨

Credits: Image by storyset