타입스크립트
목표
유효한 프로그램은 통과시키고 무효한 프로그램에는 오류를 발생시키는 것
타입스크립트는 ‘Compiled Language' 이다.
전통적인 Compiled Language 와는 다른 점이 많다.
그래서 ‘Transpile’ 이라는 용어를 사용하기도 한다.
자바스크립트는 ‘Interpreted Language’ 이다.
컴파일이 필요 O
컴파일이 필요 X
컴파일러가 필요 O
컴파일러가 필요 X
컴파일 하는 시점 O → 컴파일 타임
컴파일하는 시점 X
컴파일된 결과물을 실행
코드 자체를 실행
컴파일된 결과물을 실행하는 시점
코드를 실행하는 시점 O → 런타임
강의 요약
ts-node
TypeScript 코드를 JavaScript로 컴파일하지 않고 직접 실행시키는 라이브러리
Typescript REPL
타입의 재사용
blah blah
타입 추론
모든 타입을 선언을 해줘야 할까? 선언이 꼭 필요한 상황과 아닌 상황을 생각해보자.
키워드 정리
REPL (Read-Eval-Print-Loop)
입력한 소스코드를 읽고(Read) 평가(Eval)하고 결과를 출력(Print)하는 과정을 반복(Loop)
REPL 개발 도구
브라우저 개발 도구
터미널/쉘
온라인 컴파일러(예시: Repl.it, jsfiddle.net, jsbin.com)
온라인 정규식 유효성 검사기
Interface vs Type
Type Alias 정의
어떠한 것을 구현할 목적이 아닌 데이터를 담을 목적으로 만들때
Type
사용
Interface 정의
어떤 특정한 규격을 정의하거나 이 규격을 통해서 어떤 것이 구현된다면
Interface
를 사용
공통점
몇가지 기능을 제외하고 타입 별칭과 인터페이스 모두 동일하게 타입을 지정할 수 있다.
type PersonType = {
name: string;
age: number;
}
interface PersonInterface {
name: string;
age: number;
}
const person1: PersonType = {
name: '정태웅',
age: 29
}
const person2: PersonInterface = {
name: '정태웅',
age: 29
}
// 구현(implements)
class Person1 implements PersonType {
name: '정태웅';
age: 29
}
class Person2 implements PersonInterface {
nameL '정태웅';
age: 29
}
// 상속(extends) - 상속을 구현하는 방법은 다르지만 동일한 기능
interface GenderPersonInterface extends PersonInterface {
gender: 'w' | 'm';
}
type GenderPersonType = PersonType & { gender: string };
Type Alias로 상속을 구현할 때 주의점
Type Alias 내에 union이 사용된 경우 사용 X -> 정적으로 모양을 알수있는 객체 타입만 동작
차이점
Type Alias와 Interface 각각 개별적으로 가지고 있는 기능 및 특징들
선언 병합(Declaration Merging): Interface는 같은 이름으로 여러번 선언해도 컴파일 시점에서 하나로 합쳐진다
Public API에서 사용되는 타입은 항상 Inteface로 작성되어져야 하는 이유이기도 하다.
interface Person {
name: string;
age: number;
}
interface Person {
gender: string;
}
// 컴파일 시점
interface Person {
name: string;
age: number;
gender: string;
}
연산 프로퍼티(Computed Property): 대괄호([])안에 표현식(expression)을 이용해 객체의 key값을 정의하는 문법
더 활용성이 높은 타입을 선언해서 사용 가능하고 타입의 재사용성이 높아짐!
Index Type
이라고 불린다.
type Person = {
name: string;
age: number;
};
type Name = Person['name']; // 타입이 string
타입 추론
blah blah
Union Type vs Intersection Type
유니온 타입(Union Type): OR
발생할 수 있는 모든 케이스 중 하나만 할당할 때 사용
type Direction = 'left' | 'up' | 'right' | 'down';
const move = (direction: Direction) {...}
태그된 유니온(tagged Union)
Descriminated Union이라고도 불리며 공통된 속성을 이용하여 구분하기 쉽게 직관적인 코드를 작성할 수 있다.
공통된 속성을 갖는 타입들을 구분하기 위해 쓰이는
type
을 태그(tag) 또는 식별자(descriminator)라고 부른다.
type SuccessStatus = {
status: 'success'; // 태그 또는 식별자
result: {};
};
type FailedStatus = {
status: 'failed';
error: {};
};
type Status = SuccessStatus | FailedStatus;
타입 가드(Type Guard)
태그된 유니온을 활용한 타입 식별 헬퍼 함수 반환 타입의
is
구문은 함수의 반환이 true인 경우, 타입 체커에게 매개변수 타입을 좁힐 수 있다고 알려준다.
// 반환타입이 불린값이므로 보통 네이밍을 is~로 작명한다.
const isSuccessStatus = (status: Status): status is SuccessStatus => {
return 'result' in status;
};
인터섹션 타입(Intersection Type): AND
다양한 타입을 하나로 묶어서 사용할 수 있다.
type Person = {
name: string;
age: number;
}
type Worker = {
work: () => void;
}
const interWork = (person: Person & Worker) => {...};
interWork({name: '정태웅', age: 29, work: () => {}})
Optional Parameter
값이 있을수도 없을수도 있는 타입, 앞에
?
를 붙여 선언한다. Default 값을 설정해도 Optional Parameter가 된다.
interface Person {
name: string;
age: number;
gender: string;
jobs?: string; // string | undefined
}
const hab = (a: number, b?: number): number => {
return a + (b || 0);
}
hab(1, 2); // 정상 3
hab(1); // 정상 1
// default 값을 지정하면 동일한 효과! 더 깔끔하다.
cosnt hab2 = (a: number, b = 0): number => {
return a + (b || 0);
}
hab2(1); // 정상 1
타입을 집합이라 생각하기
타입을 할당가능한 값들의 집합(범위) 이라 생각하자.
타입이 값의 집합이라는 건 동일한 값의 집합을 가지는 두 타입은 같다는 의미
가장 작은 집합은 아무 값도 포함하지 않은 공집합이며 아무것도 할당 할 수 없는
never
타입이다.그 다음으로 작은 집합은 한가지 값만 포함하는 리터럴 타입
할당가능한 값들의 집합을 여러개로 묶는 경우 값 집합들의 합집합인 유니온 타입을 사용
구조적 타이핑 & 덕 타이핑
타입은 '봉인'되어 있지 않다.
자바스크립트는 본질적으로 덕 타이핑(duck typing) 기반
타입스크립트의 타입 시스템은 이러한 자바스크립트 런타임 동작을 모델링하기 위해 구조적 타이핑을 사용
& 인터섹션
& 연산자는 두 타입의 교집합을 계산한다.
인터섹션 타입의 값은 각 타입 내의 속성을 모두 포함하는 것이 일반적인 규칙이다.
두 인터페이스가 겹쳐지는 부분이 없어서 공집합이라고 예상하기 쉽다.
하지만 타입스크립트의 구조적 타이핑으로 추가적인 속성을 가지는 타입도 여전히 그 타입이라는 점을 생각해본다면
A & B
는 두 타입을 모두 갖는 타입이 된다.
interface Person {
name: string;
} /* name: string 값을 가지고만 있다면 Person
const birthPerson = {name: 'gg', birth: 0};
-> const person: Person = birthPerson; // 정상
*/
interface Lifespan {
birth: number;
} /* 동일하게 birth: Date 값을 가지고만 있다 해도 Lifespan이다.
const nameLifespan = {birth: 0, name: 'gg'};
-> const lifeSpan: Lifespan = nameLifespan // 정상
*/
/* 결국 {name: string, birth: Date, ...} 와 {birth: Date, name: string ,...}의
교집합을 생각한다면 {name: string, birth: Date}가 된다. */
type PersonSpan = Person & Lifespan;
const ps: PersonSpan = {
name: 'string',
birth: Date,
others: string;
}; /* 객체리터럴로 바로 할당하게되면 잉여속성체크가 일어나 타입 체커가 오류를 발생시킨다.*/
잉여속성 체크
객체 리터럴에 알 수 없는 속성을 허용하지 않는것, 그래서 ‘엄격한 객체 리터럴 체크' 라고도 불린다.
타입이 명시된 변수에 객체 리터럴을 할당 할 때 타입스크립트는 해당 타입의 속성이 있는지, 그리고 그 외의 속성은 없는지 확인한다.
객체 리터럴은 추가적인 속성을 허용하는 구조적 타이핑의 한가지 예외라고 생각하자
interface Person {
name: string;
}
const logName = (person: Person) => {
console.log(person.name);
};
logName({ name: '정태웅', age: 29 });
/*'{ name: string; age: number; }' 형식의 인수는 'Person' 형식의 매개 변수에 할당될 수 없습니다.
개체 리터럴은 알려진 속성만 지정할 수 있으며 'Person' 형식에 'age'이(가) 없습니다 */
/* 이렇게 오류가 발생하지 않는다면 이 코드를 보는 사람은 위 함수가 age에 관해서도 뭔가 처리할 것이다 라고 오해를 불러 일으 킬 수 있다.*/
const agePerson = {
name: '정태웅',
age: 2,
};
// 객체리터럴이 아니라면 잉여속성 체크가 일어나지 않는다
const person: Person = agePerson; // 정상
언제 잉여 속성체크가 수행되는가?
객체 리터럴을 변수에 할당할 때
객체 리터럴을 함수에 매개변수로 전달할 때
오직 객체 리터럴에만 적용된다.
객체 리터럴일 때만 이런 식의 타입 검사가 수행되는 이유
속성이 추가로 입력되었지만 그 속성이 "실제로 사용되지 않는다면" 거의 항상 오타가 발생한 경우이거나 API를 잘못 이해한 경우이기 때문입니다.
unknwon vs never
Last updated