타입스크립트 기초 - 20

Stulta Amiko·2022년 8월 9일
0

타입스크립트 기초

목록 보기
20/24
post-thumbnail

타입 가드

다음과 같은 두개의 타입이 있다.

export class Bird {fly() {console.log(`Flying`)}}
export class Fish {swim(){console.log(`Swimming`)}}

BirdAndFish.ts

import { Bird,Fish } from "./BirdAndFish";

const flyOrSwim = (o:Bird|Fish): void =>{

}

BirdAndFish-test.ts

위 코드에서 flyOrSwim 함수를 보면 파라미터가 구체적으로 fish인지 bird인지 알 수가 없다.

instanceof 연산자

그럴때 자바스크립트에서 제공하는 instanceof 연산자를 이용할 수 있다

import { Bird,Fish } from "./BirdAndFish";

const flyOrSwim = (o:Bird|Fish): void =>{
    if(o instanceof Bird){
        (o as Bird).fly()
    }else if(o instanceof Fish){
        (<Fish>o).swim()
    }
}

const a:Bird = new Bird()
flyOrSwim(a)

위와같이 instanceof 연산자를 이용하면 정상적인 결과가 나온다.
bird와 fish의 방식의 차이가 있는데 둘 다 사용가능하다는 것을 암시한다.

타입가드

하지만 타입스크립트에서 타입가드 라는것이 존재한다.
타입가드는 타입을 변환하지 않은 상태에서 변환하지 않은 코드 때문에 비정상적으로 종료되는 상황을 보호해주는 것을 의미한다.

코드에서 마치 instanceof처럼 동작하는 함수를 구현할 수 있다.
타입가드 기능을 하는 함수를 구현할 수 있다는 말이다.
타입 가드 기능을 하는 함수는 다음처럼 함수의 반환 타입부분에 is 라는 이름의 연산자를 사용해야한다.

import { Bird,Fish } from "./BirdAndFish";

export const isFlyable = (o: Bird|Fish): o is Bird => {
    return o instanceof Bird
}
export const isSwimmable = (o: Bird|Fish): o is Fish => {
    return o instanceof Fish
}

isable.ts

위와같은 형식으로 타입 가드 함수를 만들어준다.

import { Bird,Fish } from "./BirdAndFish";
import { isSwimmable,isFlyable } from "./isable";

const flyOrSwim = (o:Bird|Fish): void =>{
    if(isFlyable(o)){
        o.fly() 
    }else if(isSwimmable(o)){
        o.swim()
    }
}

const a:Bird = new Bird()
flyOrSwim(a)

사용은 위와같이 한다. 기존 코드에서 if문 내부 조건문이 변경된것 말고는 없다.

위코드를 실행시키면 결과가 동일하게 나온다는 것을 알 수 있다.

F-바운드 다형성

타입스크립트에서 this 키워드는 타입으로도 사용된다. this가 타입으로 사용되면 객체지향 언어에서 의미하는 다형성 효과가 나타나게 된다.
일반적인 다형성과 구분하기 위해 this타입으로 인한 다형성을
'F-바운드 다형성' 이라고한다.

F-바운드 타입

F-바운드 타입이란 자신을 구현하거나 상속하는 서브타입을 포함하는 타입을 말한다.
다음 IValueProvider<T>는 특별히 자신을 상속하는 타입이 포함되어 있지않은 일반타입이다.

export interface IValueProvider<T>{
    value(): T
}

다음 인터페이스는 add 메서드가 내가 아닌 나를 상속하는 타입을 반환하는 F-바운드 타입이다.

export interface IAddable<T>{
    add(value: T): this
}

다음 인터페이스는 메서드의 반환타입이 this 이므로 F-바운드 타입이다.

export interface IMultiplyable<T>{
    multifly(value: T):this
}

이제 위 세 개의 인터페이스를 이용해서 클래스를 구현 해야한다.

IValueProvider<T> 인터페이스 구현

import { IValueProvider } from "./IValueProvider";

export class Calculator implements IValueProvider<number>{
    constructor(private _value: number = 0) {}
    value(): number {return this._value}
}

위 코드는 IValueProvider<T> 인터페이스를 구현하고 있다. 이 클래스는 _value 속성을 private로 만들어 Calculator 를 사용하는 코드에서 _value 속성이 아닌 value() 메서드로 접근할 수 있게 설계되었다.

같은방식으로 StringComposer 클래스를 구현해 보자

import { IValueProvider } from "./IValueProvider";

export class StringComposer implements IValueProvider<string> {
    constructor(private _value: string = ' ') { }
    value(): string {
        return this._value
    }
}

IAddable<T>IMultiplyable<T> 인터페이스 구현

import { IValueProvider } from "./IValueProvider";
import { IAddable } from "./IAddable";
import { IMultiplyable } from "./IMultiplyable";

export class Calculator implements IValueProvider<number>{
    constructor(private _value: number = 0) {}
    value(): number {return this._value}
    add(value: number): this{
        this._value = this._value+value
        return this
    }
    multiply(value: number): this {this._value = this._value * value; return this}
}

Calculator 클래스는 메서드 체인을 이용하기 위해서 this값을 반환하는 것을 볼 수 있다.

import { Calculator } from "./Calculator";

const value = (new Calculator(1)).add(1).add(2).add(3).multiply(2).value()
console.log(value)

위 Calculator 클래스를 테스트 해보면 정상적으로 값이 나오는것을 알 수 있다.
this를 반환하기 때문에 메서드 체이닝을 사용할 수 있다.

import { IValueProvider } from "./IValueProvider";
import { IAddable } from "./IAddable";
import { IMultiplyable } from "./IMultiplyable";

export class StringComposer implements IValueProvider<string> {
    constructor(private _value: string = ' ') { }
    value(): string {
        return this._value
    }
    add(value: string):this {this._value = this._value.concat(value); return this}
    multiply(repeat: number): this {const value = this.value()
    for(let index = 0;index<repeat;index++){
        this.add(value)
    }
    return this
    }
}

stringcomposer는 위와 같이 구현하고서

import { StringComposer } from "./StringComposer";

const value = new StringComposer('hello').add(' ').add('world').multiply(3).value()
console.log(value)

위와같이 실행하게 되면

실행결과
hello worldhello worldhello world

와 같이 결과가 정상적으로 나오게된다.
클래스에 따라 반환 결과가 달라지는 것을 볼 수 있다.
this에 따라서 바뀌는데 calculator가 될 수도 있고 stringcomposer가 될 수도 있다.

이런식으로 동작하는 것을 F-바운드 다형성이라고 한다.

0개의 댓글