하얀 코딩

[TypeScript - 6] Object types (객체 타입) - type, interface 본문

TypeScript

[TypeScript - 6] Object types (객체 타입) - type, interface

whitecoding 2023. 6. 6. 19:35

type

타입스크립트에서 type 키워드는 사용자가 새로운 타입을 만들 수 있게 해주는 기능입니다. 

type은 기존 타입을 별칭(alias)으로 사용하거나, 복잡한 타입을 좀 더 간결하게 표현하는 데 사용됩니다.

 

간단한 예시로, string 타입을 가지는 Name이라는 새로운 타입을 만들 수 있습니다.

type Name = string;
let myName: Name = 'Alice'; // OK
type User = {
  name: string;
  age: number;
};

let user: User = {
  name: 'Alice',
  age: 25
}; // Ok

밑과 같이 유니언 타입, 인터섹션 타입 등 복잡한 타입을 만드는데도 type을 사용할 수 있습니다

type StringOrNumber = string | number;
type Key = 'name' | 'age';

interface

타입스크립트에서 interface는 사용자가 새로운 타입을 정의하는 방법 중 하나입니다. 

interface는 주로 객체의 형태(shape)를 정의하는데 사용되며, 클래스의 구현을 명시하는데도 사용될 수 있습니다.

아래는 사용법입니다.

//정의
interface Person {
    name: string;
    age: number;
}

//할당
let person: Person = {
    name: "John",
    age: 25
};

interface는 선택적 속성(Optional Property)도 정의할 수 있습니다. 

선택적 속성은 객체가 해당 속성을 가질 수도 있고 없을 수도 있음을 나타냅니다. 

선택적 속성을 정의할 때는 속성 이름 뒤에 ?를 붙입니다.

interface Person {
    name: string;
    age?: number; // 있어도 되고 없어도 되기 때문에 밑에는 에러가 없음.
}

let person: Person = {
    name: "John"
}; // OK

다음은 클래스에 대한 인터페이스 입니다.

interface IPerson {
    name: string;
    age: number;
    greet(): void;
}

class Person implements IPerson {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    greet() {
        console.log(`Hello, my name is ${this.name}`);
    }
}

위 코드에서 IPerson 인터페이스는 name, age 속성과 greet 메서드를 가진다는 것을 명시하고 있으며, 

Person 클래스는 이 IPerson 인터페이스를 구현합니다. 

따라서 Person 클래스는 IPerson이 요구하는 모든 속성과 메서드를 반드시 포함해야 합니다.

 

오버로드 시그니처(overload signatures)를 지원합니다.

interface에도 여러 함수 시그니처를 가질 수 있습니다. 이는 함수 오버로딩을 표현하는 데 유용합니다.

interface Example {
    (a: number): number;
    (a: string): string;
}

interface / type의 중요한 차이점

🔥 확장(extend) 

interface는 다른 인터페이스나 클래스가 확장(extend)할 수 있도록 허용하며, 

같은 이름의 인터페이스를 여러 번 선언하여 자동으로 병합(merge)되도록 허용합니다. 

반면에 type은 확장이나 병합을 유니온( | )이나 인터섹션( & )을 이용해야 합니다.

 

예시 1)

interface A { a: number };
interface B { b: number };
interface C { c: number };

type X = A | B | C; // Union Type
interface Y extends A, B, C {} // Intersection Type

예시 2)

interface User {
    name: string;
}

interface User {
    age: number;
}

let user: User = { name: 'John', age: 25 }; // OK

예시 3)

interface Interface1 {}
interface Interface2 extends Interface1 {} // OK

type Type1 = {};
type Type2 = Type1 & {}; // OK

🔥 재귀적 참조 (extend) 

interface는 자신을 참조할 수 있습니다. 이것은 재귀적인 자료구조를 나타내는 데 유용합니다. 

반면에 type에서는 이것이 직접적으로 가능하지는 않지만, box type을 통해 이를 해결할 수 있습니다.

interface TreeNode {
    value: string;
    children: TreeNode[]; // OK
}

type BoxedTreeNode = {
    value: string;
    children: BoxedTreeNode[]; // Error
}

type TreeNode = BoxedTreeNode & {
    children: TreeNode[]; // OK
}

따라서 type과 interface의 선택은 주로 개발자의 선호와 상황에 따라 달라집니다. 

코드의 목적과 구조에 따라 둘 중 더 적합한 것을 선택하면 됩니다.