[typescript] 가변성 문제 해결을 위한 제네릭 사용하기

가변성(variance)은 프로그래밍 언어에서 매우 중요한 개념 중 하나이며, TypeScript에서도 자주 다루어집니다. 특히, 제네릭을 사용하여 가변성 문제를 효과적으로 해결할 수 있습니다.

제네릭의 개념

제네릭은 일반화된 타입을 사용하여 클래스, 함수, 인터페이스를 작성할 수 있도록 하는 기능입니다. 이를 통해 코드의 재사용성과 유연성을 향상시킬 수 있습니다.

가장 간단한 예로 배열을 생성하는 함수를 작성해보겠습니다.

function createArray<T>(length: number, value: T): T[] {
    return Array.from({ length }, () => value);
}

let arr = createArray(5, "hello"); // ["hello", "hello", "hello", "hello", "hello"]

위의 예제에서 createArray 함수는 T라는 일반화된 타입을 받아들여 배열을 생성합니다. 이를 통해 다양한 타입에 대해 동작하는 유연한 함수를 구현할 수 있습니다.

가변성 문제

제네릭을 사용할 때 주의해야 할 점 중 하나는 가변성 문제입니다. 예를 들어, 부모 클래스의 제네릭 타입이 자식 클래스의 제네릭 타입으로 할당될 때, 가변성 문제가 발생할 수 있습니다.

이러한 상황에서 TypeScript에서는 막대한 안전성을 제공합니다. 이를테면, 배열의 불변성을 유지하면서 원소를 추가하거나 제거하는 등의 동작을 수행할 때 가변성 문제를 깔끔하게 해결할 수 있습니다.

제네릭을 이용한 가변성 문제 해결하기

가변성 문제를 해결하는 방법 중 하나는 ReadonlyPartial 같은 내장된 TypeScript 유틸리티 타입을 사용하는 것입니다.

다음은 이러한 유틸리티 타입을 사용하여 객체의 특정 속성을 읽기 전용(readonly)으로 만드는 예제입니다.

interface Book {
  title: string;
  author: string;
}

function printTitle(book: Readonly<Book>) {
  console.log(book.title);
}

let myBook: Book = { title: "TypeScript in Action", author: "John Doe" };
printTitle(myBook); // "TypeScript in Action"

위의 예제에서 Readonly 유틸리티 타입을 사용하여 Book 인터페이스의 속성을 읽기 전용으로 만들었습니다.

결론

제네릭을 이용하여 TypeScript에서 가변성 문제를 해결할 수 있습니다. 이를 통해 타입의 안정성과 코드의 유연성을 동시에 확보할 수 있습니다.

가변성 문제에 대한 더 자세한 정보는 TypeScript 공식 문서를 참고하시기 바랍니다.