본문 바로가기
React/TS

TypeScript 가이드2 클래스, 제네릭

by 강깅꽁 2020. 10. 21.

Class

기존 JS와 다른 점은 프로퍼티를 사전에 선언해야 한다.

class Dog {
    name: string;

    constructor(name: string){
        this.name = name;
    }

    bark(word: string){
        console.log(`bark ${word}`);
    }
}

const dust = new Dog('John');
dust.bark('food');

Class 접근 제한자

접근 제한자에는 public, protected, private가 있으며 프로퍼티 선언시에 생략하면 public이 기본이 접근 제한자가 된다.

프로퍼티 또는 메서드를 제한하는 용도로 쓰인다.

public의 경우 클래스 인스턴스, 클래스, 자식 클래스에서 사용할 수 있다.

protected는 해당 클래스, 자식 클래스에서 사용할 수 있다.

private는 해당 클래스에서만 사용할 수 있다.

 

프로퍼티 선언 및 접근 제한 간단하게 하기

class Dog {
    constructor(public name: string){
    }

    bark(word: string){
        console.log(`bark ${word}`);
    }
}

const dust = new Dog('John');
dust.bark('food');

Generic

타입을 파라미터로 받아와서 타입을 정해준다.

선언 시점에 타입을 정해주게 되는데 타입을 파라미터로 받아오게 되면 생성 시점 또는 실행 시점에 타입이 결정되게 할 수 있다. 

function getFirstOne<T>(items: T[]): T{
    return items[0];
}

// function getFirstOne<number>(items: number[]): number
getFirstOne([1,2,3]);

// function getFirstOne<string>(items: string[]): string
getFirstOne(['a','b','c']);
class Tuple<T>{
    constructor(private items: T){};
    get(): T {
        return this.items;
    }
}

const tupleA = new Tuple<[string, number]>(['abcd', 123]);
// ['abcd', 123]
tupleA.get();

Intersection과 Union 타입

 

Intersection은 다양한 타입을 하나의 타입으로 합쳐주는 역할을 한다. 

서로 다른 타입을 합치기 위해 새로운 타입을 선언하거나 class를 통해 상속하는것 대신에 유용하게 사용할 수 있다.

& 키워드를 사용하여 타입을 합친다. ex. Person & Action

interface Person {
    name: string;
}
interface Action {
    eat(food: string): void;
}

function combineTwoTypes(p: Person, a: Action): Person & Action {
    return { ...p, ...a};
}

const personAction = combineTwoTypes({ name: 'choi'}, {eat(food: string){ console.log(`${food}을 먹었습니다.`)}})
personAction.eat('meat');
personAction.name

 

Union은 여러 타입 중 하나의 타입을 사용한다는 것을 명시합니다.

| 키워드를 사용합니다. ex. string | number

 

value 변수는 string 타입 또는 number 타입을 가질 수 있습니다. 

let value: string | number;
value = 'abc';
value = 123;

 

함수에서의 Union 사용과 타입 가드

다음과 같이 각 파라미터의 타입을 비교하여 원하는 동작을 수행할 수 있다.

하지만 value와 value2의 타입은 string | number로 되어 있다.

따라서 정확한 타입 추론을 위해서는 함수 오버로드를 해줘야 한다. 

function addSomething(a: string | number, b: string | number) {
    if(typeof a === 'string' && typeof b === 'string'){
        return a+' somthing '+b;
    } 
    if(typeof a === 'number' && typeof b === 'number'){
        return a+b+1;
    } 
    throw new Error('Unhandled Type');
}

//const value: string | number
const value = addSomething('a','b');

//const value2: string | number
const value2 = addSomething(1,3);

 

정확한 타입 추론을 위한 함수 오버로드

function addSomething(a: string, b: string ): string 
function addSomething(a: number, b: number ): number 
function addSomething(a: string | number, b: string | number) {
    if(typeof a === 'string' && typeof b === 'string'){
        return a+' somthing '+b;
    } 
    if(typeof a === 'number' && typeof b === 'number'){
        return a+b+1;
    } 
    throw new Error('Unhandled Type');
}

//const value: string
const value = addSomething('a','b');

//const value2: number
const value2 = addSomething(1,3);

 

Primitive Type외의 타입 가드 

interface Person {
    name: string;
}
interface Action {
    eat(food: string): void;
}

const a: Action = {
    eat(food: string){
        console.log(`${food}을 먹었습니다.`);
    }
}

function isPerson(v: Person | Action): v is Person {
    return (<Person>v).name !== undefined;
}

function testType(v: Person | Action) {
    if(isPerson(v)){
        console.log(v.name);
    } else {
        v.eat('meat');
    }
}

testType(a);

 

타입 별칭(Type Aliases)

특정 타입이나 인터페이스를 대신하여 사용할 수 있는 타입 변수이다.

intersection 타입이나 Union타입을 지칭하는 형태로 사용할 수도 있고 interface 대신에 새로운 타입을 만들기 위해 type aliase를 사용해도 된다.

interface Person {
    name: string;
}
interface Action {
    eat(food: string): void;
}

type PersonAction = Person & Action;
type StringOrNUmber = string | number;
function createPersonAction(): PersonAction {
    return {
        name: '',
        eat(food: string): void {
            console.log(`${food}을 먹습니다.`);
        }
    }
}

//const personAction: PersonAction
const personAction = createPersonAction();

type Programmer = {
    write(code: string): void;
}

 

Index signature

동적으로 타입 속성을 정의 해주어야 할 때 사용한다.

interface Person {
    name: string;
    [key: string]: string | string[];
}

let person: Person = {
    name: 'choi',
    age: '24',
    skills: ['react', 'TS', 'etc'],
}