본문으로 건너뛰기

Study

스터디 : 타입스크립트

4번의 스터디가 종료되었다. 어려울 거라고 생각했던 ts지만 별 거 없었다.
주혁이 말론 어려운 내용들은 책에서 나오지 않았다고..
내가 이론적으로 알고있는것과는 별개로 실제로 프로젝트에 적용할 수 있을지는 잘 모르겠다.
스터디 종료 기념으로 정리를 하려고 한다.

타입스크립트란?

js는 태생적으로 유연한 언어이다. 유연성을 가진 만큼 장점도 많지만, 단점 또한 있다.
ts를 쓰게되면 코드의 자동완성으로 간편하면서 에러를 줄일 수 있다.

ts에 타입 정의하기

기본타입

string, number, boolean타입은 const age:number = 10; 처럼 간단하게 정의할 수 있다.
array타입은 string[],처럼 배열의 구성타입 뒤에[]를 붙여 만든다. tuple타입은 const info:[string,string]=['eunsu','gangdong']처럼 배열형태로 정의할 수 있다.
object 타입역시 위에 타입들처럼 간단하게 정의할 수 있지만, 그러면 객체라는 것만 알 뿐 객체의 속성에 뭐가 있는지 알 수 없다. 그래서 일반적으로 {name:string,age:number}처럼 구체적으로 써준다.

옵셔널

인자를 어떨때는 넘기고, 어떨때는 넘기고 싶지 않을 수 있다. 옵셔널 ?를 사용하여 이를 해결한다.

function func(a: string, b?: string) {}

이런식으로 정의하면 b를 인자로 넘겨줘도, 넘겨주지 않아도 된다.
별개로, b='korea'처럼 =... 을 넣어 디폴트 값을 넘겨줄 수 있다.

인터페이스

객체를 {...}처럼 사용하는데, 이렇게 되면 {...}부분이 여러번 반복되어 코드의 양이 굉장히 늘어날 수 있다.
인터페이스를 사용해 객체정의를 재사용할 수 있다.

interface person {
name: string;
age: number;
address: string;
}

const eunsu: person = {
name: 'SES',
age: 24,
address: 'Seoul',
};

interface는 중복되어 정의가능하다. 여러개를 정의하면 모든 타입이 합연산된다.

인덱스 시그니처

interface에 특정 속성들을 자유롭게 정의하고 싶을 수 있다. 가령 취미를 추가하고싶고, 키를 추가하고 싶고...

interface person {
[x: string]: string;
}
// 참고로 기본배열을 굳이굳이 인덱스시그니처로 표현하면 [index:number]:string; 이다

다음과 같이 정의하면 객체 person에 자유롭게 속성을 추가할 수 있다.
다만 코드 자동완성이 되지 않으므로, 필수속성들은 기입해놓고 유동적인 속성들만 다음과 같이 적용하는게 좋다. 혹은 옵셔널을 이용하거나.

유니언타입

|를 사용해 여러타입 중 하나의 타입을 사용할 수 있게 해준다.

function func(a: number | string) {}

유니언타입의 장점이라고 생각되는 점중 하나는 string보다 더 작은 집합으로도 정의가 가능하다는 것이다.

function func(a: 'name' | 'age') {}

다음과 같이 string 중에서도 name, age가 아니면 타입에러가 뜨게 만들 수 있다. 단점이라면, 객체등을 썼을 때 공통된 속성에 대해서만 자동완성을 제공한다는 것.
typeof나 in 혹은 타입가드를 통해 구분해주어야 한다.

인터섹션타입

타입 두 개를 합쳐서 사용할 수 있다.
예를들어 두 개의 인터페이스를 합쳐 새로운 이름의 인터페이스로 정의해 사용할 수 있다.

타입별칭

type value = string | number;

인터페이스와 비슷하게 타입을 정의할 수 있다.
타입별칭과 인터페이스는 비슷하면서도 다르다.
타입별칭은 유니언타입, 인터섹션, 유틸리티타입, 맵드타입을 사용할 수 있다.
다만 인터페이스도 제네릭을 사용할 수있고, 선언병합, 상속으로 타입확장 측면에서 유용해 인터페이스를 더 많이 사용한다고들 한다.

클래스

클래스 형태로도 ts를 사용할 수 있다. 주의할 점은, 변수들은 미리 타입 선언되어야 한다는 점이고, #name: age; 로 private하게 선언할 수 있다. private도 가능하지만 #을 사용하는 이유는, 실행시점에서의 에러까지 처리가 가능하기 때문이다.

제네릭

C++의 템플릿 개념과 비슷하다.
무슨 형태가 들어올 지 모르는 자료형에 대해 <T>를 사용해 지정하면 사용자가 지정한 타입을 읽어들여 사용한다.
extends로 오는 타입에 제약을 걸 수 있고, keyof를 사용해 객체를 유니언타입으로 전환해 복수의 가능성을 열어줄 수 있다.
다만, 자동완성 기능 사용을 위해 extends를 사용해줘야 한다.

function func<T extends { length: number }>(x: T) {}

다음과 같이 사용하면 x에 자동완성기능을 사용할 수 있다.

타입추론

변수를 초기화하거나 파라미터에 기본값을 지정하고 반환값을 설정했을 때, 적절한 값을 기반으로 타입을 정의한다.
주의할 점은 변수선언시 초기화가 동시에 이루어져야 추론이 가능하단 것이다.

타입단언

가끔식 타입을 강제적으로 선언해줘야 할 때가 있다. css의 !important를 생각해볼 수 있다.
ts가 타입이 뭔지 알아보지 못한다거나, event 같은 것들, 반복문 속에서 강제되는 타입들을 타입단언을 통해 타입을 강제할 수 있다.

null 아님 보장연산자

문이 제대로 실행되길 원하지만, null값일 수도 있어서 실행이 안된다고 하면 !.를 사용해 null이 아님을 보장해줄 수 있다.

타입가드

여러 유니언 타입 중, 각 유니언 타입마다 다른 실행결과를 만들고 싶을 때 사용할 수 있다. 대체적으로 typeof, instanceof 를 사용한다.

타입가드함수

instancce is object형식을 사용하여 타입가드함수를 만들 수 있다.

function isPerson(something: Person|Furniture) something is Person {
return (something as Person).age!==undefined;
}

function fun(something: Person|Furniture){
if(isPerson(something)){}
}

타입가드함수를 typeof, instanceof 처럼 사용하되 보다 가독성을 높일 수 있다.

타입호환

ts는 구조와 생김새로 타입을 판단하는 구조적 타이핑의 특성때문에 타입호환이 일어난다. 최소조건(등호 왼쪽에 있는게 오른쪽을 포함한다)을 만족하면 타입호환이 가능하다.

타입모듈

타입도 컴포넌트, 함수들처럼 모듈화를 시킬 수 있다.
다른 것들과 똑같이 사용할 수도 있고, import type처럼 뒤에 type을 붙일 수도 있는데, 개발자의 자유다.
다만 컴파일 과정에서 type을 적을 경우 컴파일시간이 단축되기 때문에 타입을 import할때 type을 사용하는 것이 권장된다.

유틸리티 타입

기존의 타입을 변경해 새로운 타입을 생성할 수 있다.
내장타입이기 때문에, 설정파일의 compilerOptions속성에 lib 속성을 추가해 만들 수 있다.
유틸리티, 맵드타입은 타입별칭을 통해서만 정의할 수 있다.

Pick

Pick<T,P> T 타입에서 P 속성을 뽑아 새로운 객체 생성

Omit

Omit<T,P> T 타입에서 P 속성을 제외한 속성들로 새로운 객체 생성

Partial

Partial<T> 모든 속성을 옵셔널화 시켜 새로운 객체 생성

Exclude

Exclude<U,P> U 유니온타입에서 P 속성들을 제외한 유니온 타입 생성

Record

Record<T1,T2> T1의 속성들이 key, T2가 value인 객체 생성

맵드타입

기존 정의된 타입을 통해 새로운 객체를 생성할 수 있다.

in, keyof

type KoreaPerson<T> = {
[P in keyof T]: T[P];
};

[]안에 in 을 사용해 마치 for in 문의 in처럼 타입을 순회한다.
keyof를 통해 특정 타입의 키 값들을 모아 유니언타입으로 변환시킨다. T[P][x:string]형태로 타입의 키에 접근하여 해당하는 value 값을 반환한다.

매핑 수정자

?,-,+,readonly 등을 사용하며 성질을 바꿀 수 있다.

extends 추가공부

ts에서 extends를 사용하는 경우는 세가지다.

  1. 상속시 확장 클래스, 인터페이스등을 상속받아 확장할 때 타입이름 뒤에 extends를 사용한다.

  2. 제약조건 타입 선언시, 즉 <>(식별자)안에서 사용하는 extends는 제약조건이다. 전자에 있는 타입을 후자로 제한한다.

  3. 조건부타입 타입구현 영역에 사용하는 extends는 조건부이다.

    T extends U ? X : Y

    U에 T가 포함된다면 참, 아니면 거짓을 반환한다.


    좀더 나가 infer를 사용해 추론할 수 있다.

    T extends infer U ? X : Y

    U가 추론가능한 타입이면 X, 아니면 Y를 반환한다.