TypeScript

Typescript - 고급타입

PHM 2022. 9. 16. 18:01

인터렉션 타입

type Admin = {
    name: string;
    privileges: string[];
};

type Employee = {
    name: string;
    startDate: Date;
};

type ElevatedEmployee = Admin & Employee;

 

타입 가드

type Combinable = string | number;

function add(a: Combinable, b: Combinable){
    if(typeof a === 'string' || typeof b === 'string'){	// 타입가드
        return a.toString() + b.toString();
    }
    return a + b;	// a와 b가 숫자형이어야 한다는 것을 안다.
}

- 타입가드는 유니온 타입이 지닌 유연성을 활용할 수 있게 해주며 런타임 시 코드가 정확하게 작동하게 해준다.

 

type Admin = {
    name: string;
    privileges: string[];
};

type Employee = {
    name: string;
    startDate: Date;
};

type UnknownEmployee = Employee | Admin;

function printEmployeeInformation(emp: UnknownEmployee){
    console.log('Name: '+emp.name);
    if('privileges' in emp){
        console.log('Privileges: '+ emp.privileges);
    }
    if('startDate' in emp){
        console.log('Start Date: '+ emp.startDate);
    }
}

- 사용자정의타입 유니온일 때.

 

class Car {
    drive() {
        console.log('Driving...');
    }
}

class Truck {
    drive() {
        console.log('Driving a truck...');
    }

    loadCargo(amount: number) {
        console.log('Loading cargo ...' + amount);
    }
}

type Vehicle = Car | Truck;

const v1 = new Car();
const v2 = new Truck();

function useVehicle(vehicle: Vehicle){
    vehicle.drive();
    // if('loadCargo' in vehicle){
    //     vehicle.loadCargo(1000);
    // }
    if(vehicle instanceof Truck){
        vehicle.loadCargo(1000);
    }
}

useVehicle(v1);
useVehicle(v2);

- 클래스를 사용하여 작업하는 경우 다른 유형의 타입가드도 사용할 수 있다.

- instanceof 타입가드를 이용

- instanceof 를 사용하면 객체가 클래스에 기반하는지 확인할 수 있고, 클래스에 기반한다면 loadCargo 함수를 지니고 있는지 확인할 수 있다.

 

- 결국 타입가드는 특정 속성이나 메소드를 사용하기 전에 그것이 존재하는지 확인하거나 타입을 사용하기 전에 이 타입으로 어떤 작업을 수행할 수 있는지를 확인하는 개념 또는 방식을 나타내는 용어이다

- 객체의 경우 instanceof 나 in을 사용하여 수행할 수 있고, 다른 타입들의 경우 typeof를 사용할 수 있다

 

구별된 유니언

interface Bird {
    type: 'bird';
    flyingSpeed: number;
}

interface Horse {
    type: 'horse';
    runningSpeed: number;
}

type Animal = Bird | Horse;

function moveAnimal(animal: Animal){
    let speed;
    switch (animal.type){
        case 'bird':
            speed = animal.flyingSpeed;
            break;
        case 'horse':
            speed = animal.runningSpeed;
            break;
    }
    console.log('Moving at speed: '+ speed);
}

moveAnimal({type: 'bird', flyingSpeed: 10});

- 타입 가드를 쉽게 구현할 수 있게 해주는 유니언 타입으로 작업을 수행할 때 사용할 수 있는 패턴으로 객체 타입으로 작업할 때도 사용할 수 있다.

- 인터페이스를 기반으로 구축된 모든 객체가 해당 타입을 갖도록 한다

- 주어진 속성의 존재 여부를 확인하거나 instanceof를 사용하게 아닌 실제 존재하는 속성을 사용하여 어떤 유형의 객체와 작업하고 있는지 확인할 수 있다.

- 객체와 유니언 타입을 사용하여 작업할 때 아주 유용한 패턴이라 할 수 있다.

 

형변환 ( typecasting )

- 형 변환은 타입스크립트가 직접 감지하지 못하는 특정 타입의 값을 타입스크립트에 알려주는 역할을 한다.

// const userInputElement = <HTMLInputElement>document.getElementById('user-input')!;
const userInputElement = document.getElementById('user-input')! as HTMLInputElement;

userInputElement.value = 'Hi there!';
const userInputElement = document.getElementById('user-input');

if ( userInputElement ) {
    (userInputElement as HTMLInputElement).value = 'Hi there!';
}

- 어떤 표현식이 반환하든 타입이 되도록 반드시 확인해야한다.

- 이와 달리 지원되지 않는 방식으로 해당 요소와 상호 작용하려하면 런타임 에러가 발생하거나 예기치 않은 동작이 런타임 시 발생할 수 있다.

- 느낌표를 사용하여 느낌표 앞의 표현식을 null을 반환(yield)하지 않겠다고 타입스크립트에게 인식시킬 수 있다.

 

인덱스 속성

interface ErrorContainer {  // { email: 'Not a valid email', username: 'Must start with a character!' }
    [prop: string]: string;
}

const errorBag: ErrorContainer = {
    email: 'Not a valid email!',
    username: 'Must start with a capital character!'
};

- 유연성을 제공하기에 사용하고자 하는 속성 이름과 필요한 속성의 개수를 미리 알 필요가 없다.

 

함수 오버로드

- 동일한 함수에 대해 여러 함수 시그니처를 정의할 수 있는 기능으로, 간단히 말해 다양한 매개변수를 지닌 함수를 호출하는 여러가지 가능한 방법을 사용하여 함수 내에서 작업을 수행할 수 있게 해준다.

function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: string, b: number): string;
function add(a: number, b: string): string;
function add(a: Combinable, b: Combinable){
    if(typeof a === 'string' || typeof b === 'string'){
        return a.toString() + b.toString();
    }
    return a + b;
}

const result = add('Max','Schwarz');
result.split(' ');

 

선택적 체이닝

- 정의되어 있는지 여부가 확실치 않은 요소 다음에 물음표를 추가

- 해당 부분이 존재하는지를 알려준다.

const fetchedUserData = {
    id: 'u1',
    name: 'Max',
    job: {title: 'CEO', description: 'My own company'}
};

console.log(fetchedUserData?.job?.title);

- 선택적 체이닝 연산자는 객체 데이터의 중첩된 속성과 객체에 안전하게 접근할 수 있게 해준다.

 

Null 병합

- null 데이터 처리에 도움을 주는 null 병합이라는 기능

- 어떤 데이터나 입력값이 있는데 그것이 null인지, undefined인지, 유효한 데이터인지 알 수 없을 경우, 

 

논리적 OR 연산자 사용

const userInput = null;

const storedData = userInput || 'DEFAULT';

- 이 방법의 문제는 이것이 null이나 undefined가 아닌 빈 문자열이라도 거짓 같은 값으로 처리되어 기본 폴백 값이 적용됨.

 

이중 물음표 연산자

const userInput = '';

const storedData = userInput ?? 'DEFAULT';

- null 병합 연산자

- null 이나 undefined 둘 중 하나라면 폴백을 사용, 빈문자열 허용