타입스크립트 Class 2

세나정·2023년 3월 9일
0

TypeScript

목록 보기
5/6

타입 단언 (type assertion)

먼저, 타입 단언에 대해 복습하고 갑시다 술이 덜 깬상태로 쓴 이전 글을 보면 알 수 있듯이 (사실 지금도 안 깸) 감히 내가 TS형님보다 타입을 확실하게 잘 알고 있다고 생각할 떄 청출어람 맹키로 내가 생각한 타입이 맞다고 우기는 것입니다.

웬만하면 사용하지 않는 것을 추천합니다만 DOM API와 같은 것들을 조작할 때는 매우 유용히 사용 가능합니다.

(변수 as 내가 지정할 타입) 으로 사용하면 되고 예시를 바로 보도록 합시다.

html에 다음과 같이 작성을 해봅니다

// 귀여운 디브 태그랍니다.
<body>
	<div id="root"></div>
</body>

자 이후 ts파일에서 쿼리셀렉터 메서드를 활용하여 html파일에서 선언한 div요소를 가져오도록 하겠습니다

자 두 눈 크게 뜨고 본다면 여기서 TS는 타입 추론을 Element | null 로 추론 합니다.

하지만 우리는 여기서 TS형님에게 한소리 하고 싶습니다.
아니 나는 Element만 알궈싶다궈~ null 아니라궈~~
왜냐하면 이런 것처럼 Element | null 타입의 변수를 조작할 경우에 조건문을 통해 root가 있는지 없는지를 판단하는 로직을 계속해서 작성해야하는 귀찮음이 있기 때문입니다.

게다가, 우리는 방금 귀염둥이 div를 직접 작성했기에 index.html에 id가 root인 울 div둥이가 무조건 있다고 확신할 수 있습니다.

자 이럴 경우에 타입 단언을 쓸 수 있는 겁니다 (타입단언이라 쓰고 ts형님께 대들기)

root 가 존재할 때만 가져올게욤 하고 한다면 null은 고민 안 해도 될 것 같군요.

타입 가드 (type guard)

아 이 양반 클래스라면서 왜 자꾸 이상한 거만 소개해? 라고 할 수 있지만 어차피 과거에 공부했대도 지금 까먹었을 거 압니다. 한번 더 갑시다

타입가드 입니다. 이름은 굉장히 멋있지만 사실 별 거 아닙니다.

특정 타입으로타입의 범위를 좁혀나가는 (필터링 하는) 과정 입니다.

타입가드를 할 수 있는 상황과 방법이 여러가지 이기 때문에
상황에 맞게 처리하시면 됩니다.
(말이 어려운 건 싫기 때문에 그냥 조건문으로 타입 지정 ㅋㅋ이라고 생각하면 됩니다)

- 타입에 대한 조건문

If + Typeof 를 쓰거나

만약 객체가 들어어오는 경우에는

// instanceof A를 활용하면 됩니다
Class A {
	constructor() {}
	함수()
}
이럴 때 자동으로 함수를 추론해줌미다

자 이번엔 타입가드가 필요한 상황의 예시 입니다.

union ( | )으로 하였기 때문에 공통된 속성만 접근이 가능합니다.
그래서 우리는 tony의 skill에 접근할 수 없는 겁니다.

자 여기에서
타입 단언 + 속성비교를 통해 처리해봅시다.

약간 지저분 하군요 우리는 이 코드를 커스텀 타입 가드로 리팩토링 해봅시다.

- 커스텀 타입가드

무작정 디벨로퍼면 스킬이 있다고 우기는 겁니다.
혹은 age도 우기는 겁니다.


클래스

오래 기다리셨습니다 클래스를 하도록 하죠
JS의 클래스는 Java 등의 클래스 기반의 객체지향 언어를 배운 사람들이 JS에 보다 쉽게 적응하도록 만든 문법입니다.

엥? 근데 JS의 클래스는 무려 ES6에 등장했습니다.
syntactic sugar일 뿐입니다.

그렇다면 JS의 클래스를 babel 등의 트랜스 파일러로 변경하면 어떤 모습일깝숑?

두구두구 무려 생성자함수입니다.

우리는 한번 Ts의 역사를 알고 가야하기 때문에 TS로 작성한 class 문법을 ES5와 ES2015(ES6)로 변환 해봅시다

- ES6

자, 우리는 소매치기를 당한 것 같군요 다음에서 사라진 게 뭘까요
예 바로 interface를 implements 하는 부분이 사라 졌습니다. (내 인터페이스 어디감?)

누누이 강조하지만 TS에서 타입을 위해 만든 코드는 JS로 변환하면 사라집니다.

이유요? 당연하죠 JS엔 타입따위 없으니 음하하

- ES5

과거로 돌아가 ES5를 봅시다 (저 이때 공부 시작했는딩)

클로저라는 JS의 특수성을 활용하여 캡슐화를 한 것을 볼 수 있습니다

생성자 함수를 캡슐화한 다음에 return을 해주는 문법입니다

최근에 JS를 공부한 개발자들은 평생 쓰지 않아도 되지만 요즘 기술면접에 필수 단골입니다.

(면접 얘기 나오니 괜히 말투 진지)

하여튼, 타입이 없는 기존의 JS에서는 클래스를 사용하지 않고 객체 리터럴로 작업을 해도 되지만 타입이 있는 TS에서는 다형성이라는 이득을 얻을 수 있기 때문에 클래스로 객체를 넣어주는 것이 좋습니다

특히, 인터페이스나 Type Alias는 instanceof 연산자로 타입가드를 할 수 없기 때문에 객체의 타입을 걸러줄 때는 클래스를 사용할 때에 장점이 있습니다

물론 방법은 있지만 그냥 클래스 쓰면됨요

타입 가드가 안 되는 이유는 당연히 interface는 TS로만 보여지는 부분이고 컴파일 될 때 interface는 JS 코드에 더 이상 남아있찌 않으니까욤

즉, 타입이나 인터페이스는 자바스크립트에 존재하지 않고 파라미터로 type과 interface로 타입값을 넣어줄 수 있는데
으로는 활용할 수 없음

하지만, 클래스는 값으로도 타입으로도 활용가능

예시 코드

전체 코드 전에 이렇게 보기쉽게 이미지로 본다면
Person에 구현한 자식 클래스들이 (Person에는 분명 없는뎅?)
Person 인터페이스를 인자로 받아서 사용이 가능하게 됨

그렇기에 Type guard로 person의 타입을 좁힌다..

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

class Student implements Person {
    constructor(public age: number, public name: string, private _major: string) {
    }
    get major(){
        return this._major;
    }
    study() { }
}

class Developer implements Person {
    constructor(public age: number, public name: string, private pL: string) {
    }
    develop() { }
}

class Professor implements Person {
    constructor(public age: number, public name: string, private course: string) {
    }
    teach() { }
}

function work(person: Person) {
    if (person instanceof Student) {
        person.major
        person.age
        person.name
        person.study()
    }
    if (person instanceof Developer) {
        person.age
        person.develop()
    }
}

그렇기에 인터페이스를 클래스로 구현한 경우, 클래스로 type guard를 할 수 있어집니다

인터페이스는 변수나 클래스에 구현에 사용되고

타입은 변수에 정말 타입 변수로서로 많이 활용을 함

자바스크립트에서는 #을 붙이면 프라이빗이 됨

Private 변수를 내보낼 땐 getter를 만들어서

Get major() {
  return this.major
} 

원래는 private _major : string으로 해주면됨


추가!

덕 타이핑 (duck typing)

덕 타이핑은 구조적 타이핑이라고도 불리며, 여기에서의 duck은 우리가 알고 있는 영단어 오리가 맞슴다

덕 타이핑이라고 불리는 이유는 눈을 감고, 소리를 들을 때 꽥꽥이면 오리라고 하기로 한 것처럼 걔가 어떻게 생겼던 (알고 보니 기계여도) 아 저거 오리넹 ㅋ 하는 그런 겁니다.

이를 코딩에 비유하자면 어떻게 만들어졌는지는 상관쓰지 않고 해당하는 속성 (값 및 메서드)가 있으면 같은 타입이라고 하자는 겁니당

객체 리터럴을 주로쓰는 JS 특성 상 인터페이스가 클래스에도 타이핑 될 수 있고 클래스가 객체 리터럴에도 타이핑 될 수 있음을 이제 배웠습니다.

그 예시를 보고 마무리합죠

[타입형]
type AnimalT = {
    name: string;
    age: number;
}

[인터페이스형]
interface AnimalI {
    name: string;
    age: number;
}

[클래스형]
class AnimalC {
    constructor(public name: string, public age:number) {
    }
}
// // 생성자 함수
// function AnimalC(name: string, age: number) {
//     return {
//         name: name,
//         age: age,
//     }
// }

[하지만 결과는 다 같음.]
const a: AnimalT = {
    name: ‘a’,
    age: 23,
}
const b: AnimalI = {
    name: ‘a’,
    age: 23,
}
const c: AnimalC = new AnimalC(‘a’, 23);
function bb(param: AnimalT) {
}
bb(c);
bb(b);
bb(a);
function aa(param: AnimalI) {
}
aa(c);
aa(b);
aa(a);
function cc(param: AnimalC) {
}
cc(c);
cc(b);
cc(a);

지송 한마디만 더 하고 가겠습니다.
인터페이스는 아래 예시처럼 클래스의 객체 타이핑을 가능하게 해주고, 객체 리터럴의 객체 타이핑을 가능하게 해줌디다


마무리

자 여기까지 읽었으면 꽤나 읽은 건데 약간 뭔가 맹한 기분이 들긴 할겁니다 전 그 이유를 압니다
Interface, type Alias, class까지 다 배웠는데 그럼 도대체 언제 뭘 쓰란 겁니까 예예 지금 알려드릴게욤

객체 지향적인 코드를 짜고 싶다면 객체의 타입 interface로 정하되 class로 interface를 implements 하는 방법을 사용합시다
이 방법은 실리콘밸리에서 프론트엔드 시니어 개발자로 일하시는 분의 코딩 스타일임 반박사절

나는 객체지향을 잘 모르겠다 하면 일단 객체를 interface로 무작정 만들어서
타입을 입혀보는 건 어떨까요 연습해봅시다.

profile
압도적인 인풋을 넣는다면 불가능한 것은 없다. 🔥

0개의 댓글