헷갈리는 타입스크립트들 정리1

Posted by : on

Category : myconfused   javaScript   typeScript


타입스크립트 공부를 하다보니.. 어떤게 어떻게 써야하는지 제대로 정리가 안돼서 여기다가 한번 정리하고자 한다.

1. 인터페이스 (Interface)

인터페이스는 객체의 구조를 정의할 때 사용 객체가 가져야 할 속성과 메서드의 타입을 지정할 수 있다.

언제 사용하는가?

인터페이스는 특정 객체가 가져야 할 구조를 미리 정의하고, 그 구조를 따르는 객체만 사용하고 싶을 때 사용합니다.

####주의할 점:

인터페이스는 구조적으로 유사한 객체를 관리하기에 좋지만, 너무 복잡한 구조를 정의하면 유지보수가 어려울 수 있습니다.

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

const person: Person = {
  name: "John",
  age: 30,
  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
};

2. 타입 별칭 (Type Alias)

타입 별칭은 특정 타입에 이름을 붙여 재사용할 수 있게 한다.

언제 사용하는가?

유니언 타입, 튜플 등 복잡한 타입에 이름을 붙여 가독성을 높이고 싶을 때 사용

####주의할 점:

타입 별칭은 인터페이스와 달리 병합되지 않기 때문에, 확장이 필요한 경우 인터페이스가 더 적합

type ID = string | number;

let userId: ID;
userId = 123;
userId = "abc";

3. 리터럴 타입 (Literal Type)

리터럴 타입은 특정 값 자체를 타입으로 사용할 수 있게 한다.

언제 사용하는가?

정해진 값들만 허용해야 하는 경우(예: 방향, 상태 등)에 사용.

####주의할 점:

리터럴 타입을 너무 많이 사용하면 코드의 유연성이 떨어질 수 있다.

type Direction = "up" | "down" | "left" | "right";

function move(direction: Direction) {
    console.log(`Moving ${direction}`);
}

move("up");  // OK
move("sideways");  // Error

4. 튜플 (Tuple)

튜플은 고정된 수의 요소를 가지며, 각 요소가 특정 타입을 가지는 배열

언제 사용하는가?

서로 다른 타입의 값들을 함께 다뤄야 할 때 사용.

####주의할 점:

튜플의 길이가 길어지면 관리가 어려워질 수 있다

let person: [string, number];
person = ["John", 30];  // OK
person = [30, "John"];  // Error

5. 네임스페이스 (Namespace)

네임스페이스는 코드를 모듈화하여 동일한 이름을 가진 변수를 충돌 없이 사용할 수 있게 한다.

언제 사용하는가?

대규모 애플리케이션에서 이름 충돌을 피하면서 모듈화를 할 때 사용

####주의할 점:

네임스페이스는 모듈 시스템과 함께 사용할 때 혼란을 줄 수 있으므로, 모듈 시스템을 사용하는 경우에는 네임스페이스를 피하는 것이 좋다.

namespace Animals {
    export class Dog {
        bark() {
            console.log("Woof!");
        }
    }
}

namespace Vehicles {
    export class Dog {
        honk() {
            console.log("Beep!");
        }
    }
}

let pet = new Animals.Dog();
pet.bark();

let car = new Vehicles.Dog();
car.honk();


6. 인덱스 접근 타입 (Indexed Access Type)

인덱스 접근 타입은 객체 타입의 특정 속성 타입을 가져올 수 있게한다.

언제 사용하는가?

객체 타입에서 특정 속성의 타입을 재사용하고 싶을 때 유용

####주의할 점:

잘못된 속성명을 사용하면 컴파일 오류가 발생하므로 주의

interface Person {
    name: string;
    age: number;
}

type NameType = Person['name'];  // string 타입

7. 매핑된 객체 타입 (Mapped Type)

매핑된 타입은 기존 타입을 변형하여 새로운 타입을 생성할 때 사용.

언제 사용하는가?

기존 타입의 모든 속성을 변형하여 새로운 타입을 만들어야 할 때 사용

####주의할 점:

매핑된 타입은 복잡할 수 있으므로, 필요 이상으로 사용하면 코드가 이해하기 어려워짐

type ReadOnly<T> = {
    readonly [P in keyof T]: T[P];
};

interface Person {
    name: string;
    age: number;
}

const readonlyPerson: ReadOnly<Person> = {
    name: "John",
    age: 30
};

readonlyPerson.name = "Doe";  // Error

8. 유니언과 인터섹션 (Union & Intersection)

  • 유니언 타입은 여러 타입 중 하나의 타입을 허용.
  • 인터섹션 타입은 여러 타입을 모두 만족.

언제 사용하는가?

유니언 타입은 다형성을 제공하며, 인터섹션 타입은 여러 타입의 결합된 기능이 필요할 때 사용

####주의할 점:

인터섹션 타입을 사용할 때 속성이 충돌하지 않도록 주의

type A = { name: string };
type B = { age: number };

type AB = A & B;  // { name: string; age: number }
type AorB = A | B;

let person1: AB = { name: "John", age: 30 };  // OK
let person2: AorB = { name: "Doe" };  // OK


9. 제네릭 (Generic)

제네릭은 타입을 변수처럼 다뤄서 다양한 타입에 대해 재사용 가능한 코드를 작성할 수 있게 해줌

언제 사용하는가?

여러 타입에 대해 동일한 로직을 적용할 때 사용

####주의할 점:

제네릭을 남용하면 코드가 복잡해질 수 있습니다. 필요할 때만 사용

function identity<T>(arg: T): T {
    return arg;
}

let output = identity<string>("Hello");


10. 컨디셔널 타입 (Conditional Type)

컨디셔널 타입은 조건에 따라 타입을 선택할 수 있게 해줌

언제 사용하는가?

조건에 따라 타입을 다르게 적용해야 할 때 유용합니다.

####주의할 점:

컨디셔널 타입은 복잡한 논리를 담을 수 있으므로, 지나치게 복잡하게 만들지 않도록 주의

type IsString<T> = T extends string ? true : false;

type A = IsString<string>;  // true
type B = IsString<number>;  // false

About 유재석
유재석

개발자 유재석 입니다. Web Developer.

Email : jaeseok9405@gmail.com

Website : https://github.com/yoo94