들어가며
단순히 타입스크립트 뿐만 아니라 다른 언어의 타입은 어떻게 작용하는 지 그리고 타입스크립트는 어떤 특징을 가지고 있는지 설명해주면서 알려준다.
한 언어에 능통하게 되면, 추후 다른 언어를 배울 때 쉽다고 한다. 이 책을 보면서 왜 그런지에 대해서 느끼게 되었다.
또한 enum이라던가 type과 interface등 어떠한 상황에 쓰는지에 대한 배민팀에 대한 고민도 같이 읽을 수 있어서 좋았다.
목차는 1. 타입, 2. 타입시스템, 3. 원시 타입 4. 객체 타입 총 4가지다.
1. 타입
책에서는 타입을 크게 5가지 관점에서 다룬다.
- 자료형으로서의 타입
- 집합으로서의 타입
- 정적과 동적 타입
- 강타입과 약 타입
- 컴파일 방식
자료형으로서의 타입
타입스크립트는 자바스크립트의 슈퍼셋언어이다. 따라서 자바스크립트와 굉장히 유사한 관계가 있다.
따라서 타입스크립트의 자료형으로서의 타입 또한 자바스크립트와 같은데, 자료형의 타입이 필요한 이유는 메모리를 효율적으로 쓰기 위해서다. (데이터의 종류에 따라 필요한 메모리 공간이 다르므로)
흔히 백준에서 알고리즘 문제를 풀다보면, 자바스크립트가 데이터 타입이 조금 더 빡빡한 c나 자바보다 메모리 부족 문제를 쉽게 겪는다.
자바스크립트는 ECMAScript 표준으로 7가지 데이터 타입을 갖는다.
- undefined
- null
- Boolean
- String
- Symbol
- Numeric
- Object
집합으로서의 타입
타입스크립트에서는 값이 가질 수 있는 유효한 범위의 집합을 제한해준다.
정적 타입과 동적 타입
자바스크립트는 동적타입이고 타입스크립트는 정적타입이다.
정적이냐 동적이냐의 구분은 변수의 타입이 언제 정해지냐에 따라서 결정되는데,
- 동적 타입 : 런타임
- 정적 타입 : 컴파일
이러한 동적 타입 시스템은 개발 과정에서는 에러가 없지만 프로그램이 실행 단계에서 에러 혹은 예상치 못한 결과가 생길 수 있다.
강타입과 약타입
암묵적 타입 변환 (런타임에 타입이 자동으로 변경되는지) 에 따라서 강타입과 약타입을 구분한다.
책에서는 -를 예시로 설명해주는데 C++ , 자바, 파이썬 , 루비, 자바스크립트, 타입스크립트를 분류하면 아래와 같다.
강타입 | 약타입 |
파이썬, 루비, 타입스크립트 | C++,자바,자바스크립트 |
약타입의 언어 또한 동적 타입처럼 런타임에 예상치 못한 에러를 발생시킬 수 있다.
컴파일 방식
컴파일이란 보편적으로 컴퓨터가 이해할 수 있는 기계어로 바꿔주는 과정이다.
이떄 타입스크립트는 컴파일의 결과물이 예외적으로 자바스크립트 파일이다.
이유는 자바스크립트의 런타임 에러를 컴파일 단계에서 잡기 위한 목적으로 생성 되었기 때문이다.
요약하자면 타입스크립트는
undefined, null, Boolen, Numeric, Object, String, Symbol의 자료형 타입을 가진 강타입의 동적 타입이다.
타입스크립트는 집합으로서의 의미를 가지며 컴파일 시 자바스크립트 파일이 생긴다.
2. 타입 시스템
타입스크립트의 특징은 5가지가 있다.
1. 타입 에너테이션 방식
let isDone: boolean = false
변수 이름뒤에 :type 구문을 붙여 데이터 타입을 명시해준다. 점진적 특징을 가져서 선언부 제거해도 되나, 타입스크립트의 타입시스템이 타입을 추론하는 과정에서 어려움을 겪는다.
(타입이 자바스크립트와 다르게 Boolean이 아닌 boolean이다)
2. 구조적 타이핑
타입을 사용하는 언어중에서는 타입이 컴파일 이후에도 이름으로 남는 경우가 있다.
이를 구체화한 타입 시스템이라고 하는데, 타입스크립트는 이와 다르다.
타입스크립트는 구조로 타입을 구분한다.
interface Developer {
faceValue : number;
}
interface BankNote {
faceValue : number;
}
let developer: Developer = {faceValue :52};
let bankNote: BankNote = {faceValue :52};
developer = bankNote;
bankNote = developer;
구체화한 타입 시스템에서는 developer 와 bankNote의 타입 이름이 다르니깐 서로 할당할 수 없어야 한다.
하지만 구조적 타입 시스템이기에 타입스크립트에서는 마지막 2줄이 가능하다.
구조적 서브 타이핑
구조적 서브타이핑이란 객체가 가지고 있는 속성을 바탕으로 타입을 구분하는 것이다.
interface Developer {
faceValue : number;
}
interface FrontendDev {
faceValue : number;
major : String
}
let developer: Developer;
let frontendDev: FrontendDev = {faceValue :52, major: "React" };
developer = frontendDev;
developr 과 frontendDev는 다른타입이지만 faceValue를 공통적으로 가져서 할당할 수 있다.
이는 함수의 매개변수에도 적용이 된다. 또한 상속 역시 구조적 타이핑을 기반으로 하고 있다.
class Person {
name : string;
age : number;
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
}
class Developer {
name : string;
age : number;
sleepTime : number;
constructor(name:string, age:number, sleepTime : number){
this.name = name;
this.age = age;
this.sleepTime = sleepTime;
}
}
function greet(p:Person {
console.log(`Hello, I'm'${p.name}`);
}
const developer = new Developer("zig",20,7);
gree(developer);
타입 A가 타입 B의 서브 타입이라면 A 타입의 인스턴스는 B타입이 필요한 어디든 위치할 수 있다.
구조적 타이핑인 이유
타입스크립트가 구조적 타이핑을 채택한 이유는 자바스크립트를 모델링한 언어이기 때문이다.
자바스크립트는 덕 타이핑 기반으로 어떤 함수의 매개변수값이 올바르게 주어진다면 그 값이 어떻게 만들어졌는지 신경쓰지 않는다. 하지만 덕 타이핑도 속성을 바탕으로 타입을 검사하지만, 런타임에 체크를 한다.
하지만 구조적 타이핑은 컴파일 타이밍에 타입을 검사한다.
구조적 타이핑의 결과
interface Cube {
width: number;
heigth: number;
depth: number;
}
function addLines(c: Cube) {
let total = 0;
for (const axis of Object.keys(c)) {
const length = c[axis];
total += length;
}
}
const namedCube = {
width: 6,
heigth: 5,
depth: 4,
name: 'SweetCube',
};
addLines(namedCube);
구조적 타이핑이기에 아래와 같은 경우엔 에러가 생긴다. Cube의 타입이 당연히 number일 거라 생각했지만 name은 string 타입이다. 이러한 한계를 극복하고자 유니온이라는 방법이 생긴다.
3. 점진적 타입 확인
점진적 타입 검사란 컴파일 타임에 타입을 검사하면서 필요에 따라 타입 선언 생략을 허용하는 방식이다.
타입 선언을 생략하면 동적 검사를 수행하고 암시적 타입 변환이일어난다.
function add(x,y){
return x+y;
}
// 암시적 타입 변환 결과
function add(x:any,y:any):any;
자바스크립트의 슈퍼셋 언어이기에 자바스크립트의모든 코드는 타입스크립트 코드로 봐도 무방하다.
따라서 .ts 파일에 자바스크립트 문법을 소스코드를 작성해도 문제가 생기지 않고, 이때 점진적 타이핑이라는 특징이 유효하게 사용가능하다. 다만 정적 타입의 정확성을 100%보장하지는 않는다.
const names = ["zig,colin"];
console.log(names[2].toUpperCase());
//TypeError names[2]는 undefined라서 toUpperCase가 불가능하다.
4. 값 vs 타입
타입스크립트는 컴피알이 되면 자바스크립트로 바뀌게 된다.
이때 컴파일이 되면 사라지는 단순히 타입만 알려주는 것과, 실제로 사용되는 값(메모리에 저장하는 데이터)이 구분되어야 한다.
이때 변수의 이름과 type, interface 키워로 설정한 커스텀 타입의 이름은 서로 충돌하지 않는다. (타입은 별도의 네임스페이스에 저장된 후 런타임에는 제거되기 떄문)
다만 타입스크립트에서 값과 타입의 구분은 맥락에 따라 달라지기에 주의할 필요는 있다.
예시로는 구조분해 할당을 들 수 있는데 구조분해 할당할 경우 3번같이 사용하게 되면 key Value로 해석하고 오류가 생긴다.
// 일반적인 타입
function email(options : {person:Person; subject:string;body:string}){
//...
}
// 자바스크립트에서 구조분해 할당할 경우
function email({person, subject,body}){
//...
}
// 타입스크립트에서 잘못된 경우
// key Value로 해석될 여지가 있음
function email({person:Person; subject:string;body:string}){
//...
}
// 제대로 사용
function email({person, subject,body}):{person:Person; subject:string;body:string}{
//...
}
또한 enum과 Class의 경우에 값과 타입이 둘 다 존재해서 주의해야 한다.(타입이 런타임에 실제 값으로도 사용될 수 있다.)
enum이 타입으로 쓰이는 경우
enum WeekDays {
MON = 'Mon',
TUES = 'Tues',
WEDNES = 'Wednes',
THURS = 'Thurs',
FRI = 'Fri',
}
type WeekDaysKey = keyof typeof WeekDays;
function printDay(key: WeekDaysKey, message: string) {
const day = WeekDays[key];
if (day <= WeekDays.WEDNES) {
console.log(`It's still ${day}, ${message}`);
}
}
printDay('TUES', 'wanna go home');
값으로 쓰이는 경우
enum MyColors {
BLUE = '#0000FF',
YELLOW = '#FFFF00',
}
function whatBlueColor(palette: { BLUE: string }) {
return palette.BLUE;
}
whatBlueColor(MyColors);
심볼이 값으로 사용된다는 것은 타입스크립트 컴파일 이후에도 자바스크립트에서 해당 정보가 남아있다는 뜻이다.
각각 키워드를 값과 타입으로 분류하면 아래와 같다.
키워드 | 값 | 타입 |
class | Y | Y |
enum | Y | Y |
const, let ,var | Y | N |
function | Y | N |
namespace | Y | N |
type | N | Y |
interface | N | Y |
5. 타입 확인하는 방법
typeof 연산자를 통해서 7가지 기본 데이터 타입과 (Boolean, null, undefined, Number,BigInt, String,Symbol) 과 Function, 호스트 객체 , 오브젝트 객체 를 얻을 수 있다.
이때 typeof 연산자는 자바스크립트에서도 존재하며 값에 쓰일 때와 타입에 쓰일 때가 다르다.
값 : javascript의 런타임의 typeof 연산자가 된다.
타입 : 타입스크립트의 typeof가 된다.
class의 경우에는 값으로 사용할 때는 결국 함수이므로 function 타입인데, 타입으로 쓰이는 경우는 생성자 함수를 뱉는다.
instanceof 연산자를 통해서 타입이 보장된 상태에서 안전하게 값의 타입을 정제하여 사용할 수 있다.
as 키워드를 사용하는 타입 단언을 통해서, 강제 형 변환과 유사한 기능으로 타입을 지정할 수 있다. (개발자가 해당 값의 타입을 더 잘 파악할 수 있는 경우.. 대신 런타임에서는 효력이 없다.)
타입가드를 통해 타입을 보장할 수도 있다.
3. 원시 타입
자바스크립트의 슈퍼셋이기 때문에, null과 undefined를 제외한 모든 원시값은 해당 원시값을 래핑한 객체를 가지며 이름이 파스칼 표기법으로 쓰지 않는다.
- boolean
Truthy와 Falsy를 제외한 true, false. - undefined
아직 할당되지 않음 - null
undefined와 마찬가지로 존재하지 않음을 알리는 값인데 없다를 강조할 떄 null을 쓴다.(undefined는 아직 없는 것일 수도 있어서) - number
자바와 달리 숫자를 number로만 사용하고, NaN과 Infinity도 포함 - bigInt
2**53-1 를 넘어가는 수를 처리할 수 있는데, number와 상호 작용이 되지 않는 서로 다른 타입이다. - string
문자열 (공백도 포함함) - symbol
ES2015에 도입된 타입으로 어떤 값과도 중복되지 않는 유일한 값
4. 객체 타입
- object
원시 타입이 아닌 모든 값이 해당되어 사용하는 것이 any 와 마찬가지로 추천되진 않는다. - {}
객체 리터럴 방식으로 객체를 생성할 때 쓰인다. 타입스크릅테엇는 객체를 타이핑할 떄도 중괄호를 쓸 수 있는데, 중괄호 안에 객체의 속성 타입을 지정해주는 방식으로 쓰인다.const noticePopup: { title: string; description: string } = { title: 'IE 지원 종료', description: '2022.07부로 종료', //startAt : "2022.07.15" // 지정 타입에 없을므로 오류 생김 };
- array
number [] 와 같이 쓰이는 방법과 Array 키워드로 쓰는 방법이 있다.
튜플 타입도 대괄호라 사용한다는 점을 주의해야함 - type과 interface 키워드
타입스크립트에서만 독자적으로 사용할 수 있는 키워드로 객체를 타이핑하기 위해 쓰임.
type NoticePopupType ={ { title: string; description: string } } const noticePopup:NoticePopupType = { title: 'IE 지원 종료', description: '2022.07부로 종료', };
- function
자바스크립트에서 함수도 일종의 객체로 간주하지만 typeof를 쓸 경우 별도의 function 타입이 존재한다.
이때 객체 타이핑과 다르게 주의해야할 점이 2가지가 있다.
1. typeof 연산자로 확인한 function 키워드 자체를 type으로 쓰지 않음
2. 함수는 매개 변수 목록을 받을 수 있는데, 타입스크립트에서는 매개변수도 별도 타입을 지정해야 함
위 예시는 함수를 작성할 떄 type을 쓰는 법이고, 함수 자체 타입은 호출 시그니처를 정의하는 방식을 사용하여 지정할 수 있다.function add (a:number,b:number):number{ return a+b; }
type add = (a:number, b:number) =>number; // 화살표 함수 방식으로만 정의
'독서' 카테고리의 다른 글
우아한 타입스크립트 with React -6장 타입스크립트 컴파일 (0) | 2024.02.19 |
---|---|
우아한 타입스크립트 with React -5장 타입활용하기 (0) | 2024.02.17 |
우아한 타입스크립트 with React -4장 타입확장하기 * 좁히기 (0) | 2024.02.15 |
우아한 타입스크립트 with React -3장 고급타입 (0) | 2024.02.14 |
우아한 타입스크립트 with React -1장 들어가며 (0) | 2024.02.11 |