본문 바로가기
개발/타입스크립트

타입 스크립트 기초 4 - 제네릭, 타입제한, 타입추론, 타입단언, 타입가드, 타입호환

by 뇽.뇽 2024. 1. 10.
반응형
반응형
function logText(text: string) {
    console.log(text);
    return text;
}

function logNumber(num: number) {
    console.log(num);
    return num;
}

console에 출력을 해주는 두 함수가 있다. 동일한 기능이지만 매개변수 타입이 string, number로 다르기 때문에 저렇게 사용한 것이다.

 

제네릭 선언

function logText<T>(text: T):T {
    console.log(text);
    return text;
}

함수의 중복선언으로 인해 코드가 낭비되므로 제네릭을 통해 구현하는 것이 좋다.

 

function logText(text: string | number) {
    console.log(text);
    return text;
}

물론 이렇게 선언하여 사용하여도 문제가 없지만 코드의 확장성을 고려하면 제네릭을 사용하는것이 좋으며, string과 number 둘 다 사용할 수 있는 함수만 사용이 가능하다.

 

타입제한

첫번째 방법 - 기본

function logTextLength<T>(text: T[]): T[] {
    console.log(text.length);
    text.forEach(function (text) {
        console.log(text);
    });
    return text;
}
logTextLength<string>(['hi', 'abc']);

함수를 사용할때 제네릭타입에 string을 써 넣어 타입을 제한할 수 있다.

 

 

두번째 방법 - 정의된 타입 이용하기

interface LengthType {
    length: number;
}
function logTextLength<T extends LengthType>(text: T): T {
    text.length;
    return text;
}
logTextLength('a'); // 사용가능 -> 문자열은 기본적으로 length 속성이 존재
logTextLength(10);  // 사용불가
logTextLength({ length: 10 });  // 사용가능

length라는 속성이 있는 객체로 제한

 

 

세번째 방법 - keyof

interface ShoppingItem {
    name: string;
    price: number;
    stock: number;
}

function getShoppingItemOption<T extends keyof ShoppingItem>(itemOption: T): T {
    return itemOption;
}
// getShoppingItemOption(10);	// 사용불가
// getShoppingItemOption<string>('a');	// 사용불가
getShoppingItemOption('name');

T extends keyof ShoppingItem을 사용하게 된다면 getShoppingItemOption() 매개변수로는 'name',  'price',  'stock'  속성이  들어갈 수 있게 제한된다. 

 

타입추론

타입스크립트는 타입을 선언하지 않으면 추론해서 자동으로 타입을 지정한다.

function getB(b) {
    var c = 'hi';
    return b + c;
}

리턴 타입은 무조건 string이다. string과 뭐를 연산하든 string이 나오기 때문이다.

 

타입단언

var a;
a = 20;
a = 'a';
var b = a as string;

as string을 적어줌으로서 타입스크립트가 추론을 하지않고 string으로 고정하게 된다.

 

타입가드

interface Developer {
    name: string;
    skill: string;
}

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

function introduce(): Developer | Person {
    return { name: 'Tony', age: 33, skill: 'Iron Making'}
}
var tony = introduce();
console.log(tony.skill);

if ((tony as Developer).skill) {
    var skill = (tony as Developer).skill;
    console.log(skill);
} else if ((tony as Person).age) {
    var age = (tony as Person).age;
    console.log(age);    
}

// 타입 가드 정의
function isDeveloper(target: Developer | Person): target is Developer {
    return (target as Developer).skill !== undefined;
}

if (isDeveloper(tony)) {
    console.log(tony.skill);
} else {
    console.log(tony.age);
}

타입 가드를 통해 타입을 지정할 수 있다. isDeveloper()에서 target이 Developer이면 true를 반환한다.

 

타입호환

인터페이스와 클래스

// 인터페이스
interface Developer {
    name: string;
    skill: string;
}
// interface Person {
//     name: string;
// }
class Person {
    name: string;
}

var developer: Developer;
var person: Person;
developer = new Person();
// developer = person;  // O
// person = developer;  // X

부분집합처럼 큰 범위에 작은 범위를 선언이 가능하나 그 반대의 경우는 불가능함

 

함수와 제네릭

// 함수
var add = function(a: number) {
    // ...
}
var sum = function(a:number, b: number) {
    // ...
}
sum = add;  // O
// add = sum;  // X

// 제네릭
interface Empty<T> {
    // ..
}
var empty1: Empty<string>;
var empty2: Empty<number>;
empty1 = empty2;    // 사용가능 
empty2 = empty1;    // 사용가능

interface NotEmpty<T> {
    data: T;
}
var notempty1: NotEmpty<string>;
var notempty2: NotEmpty<number>;
notempty1 = notempty2;  // 사용불가
notempty2 = notempty1;  // 사용불가

함수나 제네릭 같은 경우도 더 넓은 범위 안에 작은 범위를 선언이 가능하다.

반응형