이 포스팅은 [DreamCoding 엘리님의 타입스크립트 강의](https://academy.dream-
coding.com/courses/typescript)을 복습하며 작성되었습니다.
아래 코드는 number 또는 null타입의 인자를 받고, null인 경우 에러메세지를 출력하고 number 타입인 경우 값을 그대로 리턴하는 함수입니다!
function checkNotNullNumber(arg: number | null): number {
if (arg == null) {
throw new Error("not valid type!");
}
return arg;
}
그런데 여기서 number타입 말고 다른 타입의 값들도 인자로 받아 검사하고 싶으면 어떻게 할까요?
아래 코드는 any타입 또는 null을 인자로 받을 수 있는 함수입니다.
any타입이니 number타입 외에 다른 타입들도 입력받을수 있겠죠?
function checkNotNullAny(arg: any | null): any {
if (arg == null) {
throw new Error("not valid number!");
}
return arg;
}
그런데 문제가 있습니다❗️ 이 함수의 리턴값도 any타입이라는 것이죠.
아래 변수 result
에는 어떤 타입의 값도 올 수 있습니다.
어떤 값이 들어오든 타입에러가 나지 않고 타입 보장이 안되는 문제가 발생합니다!
let result = checkNotNullAny(123);
result = checkNotNullAny("abc");
result = true;
그렇다면 어떤 타입이든 인자로 받을 수 있으면서 리턴 후에도 타입을 보장하며 안전하게 사용할 수 있는 방법은 없을까요? 이럴 때 제네릭 사용합니다!
아래 코드의 함수는 인자로 들어온 값의 타입대로 리턴 후 타입도 결정됩니다.
arg에 boolean타입이 들어오면 리턴 후에도 arg값은 boolean타입인 것이죠 💡
function checkNotNull<T>(arg: T | null): T {
if (arg == null) {
throw new Error("not valid type!");
}
return arg;
}
resutl1의 경우를 보면, checkNotNull함수의 인자로 number타입이 들어갔으니 변수 result1의 타입도 number가 될 것입니다. 이때 result1에 문자열 값을 재할당 하려고 하면 Type Error가 발생하는 것이죠!
const result1: number = checkNotNull(123);
result1 = "abc"; // Type Error
const result2: boolean = checkNotNull(true);
const result3: boolean = checkNotNull("hi"); // Type Error
이렇게 Generic을 활용하면 타입을 보장하며 안전하게 사용할 수 있습니다.
이번에는 인자 두개를 받아서 그대로 다시 리턴하는 클래스를 만들어보겠습니다.
먼저 Interface를 Generic으로 구현했습니다.
Interface Either
는 left, right 메서드를 갖고 있습니다.
그리고 각각 L과 R을 리턴합니다.
interface Either<L, R> {
// interface를 제네릭으로 구현
left: () => L;
right: () => R;
}
아래 코드의 Generic으로 만든 class인 SimpleEither
은 Interface Either
을 상속받습니다.
멤버변수 leftValue와 rightValue은 각각 generic타입 L, R인을 자신의 타입으로 갖습니다. 메서드 left, right는 두 멤버변수를 그대로 리턴합니다.
class SimpleEither<L, R> implements Either<L, R> {
constructor(private leftValue: L, private rightValue: R) {}
left(): L {
return this.leftValue;
}
right(): R {
return this.rightValue;
}
}
인스턴스 example1
을 생성합니다.
멤버 변수로 들어온 값의 타입(number)대로 리턴됩니다.
const example1: Either<number, number> = new SimpleEither(4, 5);
example1.left(); // 4
example1.right(); // 5
인스턴스 example2를 생성합니다.
: Either<number, string>
이렇게 타입 명시하는 부분을 생략할 수 있습니다!
const example2: Either = new SimpleEither(3, "hello");
example2.left(); // 3
example2.right(); // hello
인자로 들어가는 값과 다른 타입을 명시하면 타입에러가 납니다.
const example3: Either<number, boolean> = new SimpleEither(3, "hello");
// --> Error: Type 'SimpleEither<number, string>' is not assignable to type 'Either<number, boolean>'. The types returned by 'right()' are incompatible between these types. Type 'string' is not assignable to type 'boolean'