인프런의 타입스크립트 입문 - 기초부터 실전까지 온라인 강의 수강한 내용 정리 레포지토리
Typed JavaScript : 자바스크립트에 타입 부여한 언어
- 자바스크립트와 다르게 컴파일 필요
- 장점 = intellisense
- 코드 작성 중 필드명 자동완성
- 타입에서 제공하는 기본 속성 활용 가능
sum(a: number, b: number): number { return a+b; } const result = sum(10, 20); // result: number result.toLocaleString(); // number타입에서 제공하는 속성 자동완성됨
Type Annotation(타입 표기) : : 이용해서 JS 코드에 타입 정의
const {변수명}: {타입} = {초기값};
function {함수명}({파라미터명}: {타입}): {리턴타입} {...};
- string
- number
- boolean
- Array
- any
- void
- 함수의 리턴타입 정하지 않을 때 사용 (5.any 아님)
- tuple
- 모든 요소의 타입이 정해진 길이 고정 배열
const address: [string, number] = ['gangnam', 100]; - enum
- 상수 집합
enum Shoes { Nike = '나이키', Adidas = '아디다스', } const myShoes = Shoes.Nike; // -> '나이키'enum Avengers { Capt, IronMan, Thor } // 초기화하지 않은 경우 숫자형 (0부터 autoincreasing) enum Avengers { Capt = 2, IronMan, Thor } // 인덱스 임의 지정 가능 let hero: Avengers = Avengers[2]; // -> Capt let hero: Avengers = Avengers[4]; // -> Thor - never
- 함수의 끝에 절대 도달하지 않음
function neverEnd(): never { while (true) {}; }
- 함수의 타입 정의하는 방법 = 파라미터, 반환값의 타입 정의
- 파라미터 제한 하는 특성: ex. 함수 파라미터 2개 선언 후 2개 이상or이하 작성시 에러
- cf. JS는 유동적, 에러발생X
- 옵셔널 파라미터: 파라미터 타입 정의할때
?붙여서 선택적으로 사용function log(a: string, b?: string): string { return a + b; } console.log('hello'); // --==>> OK console.log('hello', 'world'); - rest 문법: 파라미터 개수 유동적으로 설정
function sum(a: number, ...rest: number[]): number { const total = 0; for (let key in rest) { total += key; } return a + total; }- cf. rest 문법 VS spread 문법
spread rest 개념 펼치다기존 객체/배열 변동없이 하위 항목 모두 설정나머지0, 1, ... 특정 인덱스값 외 나머지사용 객체, 배열 객체, 배열, 함수 파라미터
- cf. rest 문법 VS spread 문법
interface Person {
name: string; // 공통 속성
age: number;
}
interface Developer {
name: string; // 공통 속성
skill: string;
}
- Union 타입 = 교집합
|= 공통 속성에만 접근 가능function askSomeone(someone: Person | Developer) { someone.name // someone.age // someone.skill }- 타입 가드 통해서 Union 타입 중에서 특정 가능
function whoisit(someone: Person | Developer) { if (someone.name === '개발자') { // Developer console.log(someone.skill); // name, skill 자동완성 } else { console.log(someone.age); // name, age 자동완성 } }
- 타입 가드 통해서 Union 타입 중에서 특정 가능
- Intersection 타입 = 합집합
&= 모든 속성에 접근 가능function askSomeone(someone: Person & Developer) { someone.name someone.age someone.skill }
- TypeScript에서 Class는
Syntatic Sugar기능적으로 추가/변경되는 내용 없음 - 특징
- 생성자 함수 constructor() 사용 → JS와 공통점
- 생성자 함수 파라미터의 타입 정의
- 멤버변수, 접근 범위의 정의 → JAVA와 공통점
Class Person { private name: string; // #3 public age: number; readonly log: string; constructor(name: string, age: number) { // #1, #2 this.name = name; this.age = age; } } const seho = new Person('세호', 30);
- 타입을 호출부에서 파라미터처럼 설정 → 타입에 유연하게 처리
- 불필요한 오버로딩, 인터페이스 선언 등의 문제 해결
- Union 타입일 때 여러 타입에서 공통 제공하는 빌트인함수만 사용 가능한 문제 해결
- 제네릭 인터페이스/클래스 생성 가능 (단 enum, namespace는 제네릭으로 생성 불가)
- API Response 규격 설정할 때 가장 많이 사용
type ApiResponse<Data> = { data: Data; isError: boolean; }; const response: ApiResponse<{ name: string; age: number }> = { data: { name: 'name', age: 28 }, isError: false, }; - 제네릭으로 제약조건 설정 가능
function logLength<T>(text: T): T { console.log(text.length); // -> Error 어떤 타입이 설정될지 불확실하여 length 메소드 제공 여부 알 수 없음 return text; } // 1. 추론 가능하도록 설정 function logLength<T>(text: T[]): T[] { console.log(text.length); // -> OK return text; } // 2. 정의된 타입 상속(extends) interface LengthType { length: number; } function logLength<T extends LengthType>(text: T): T { console.log(text.length); // -> OK LengthType에 설정된 속성만 있으면 된다 console.log({ length: 10 }); return text; } // 3. 정의된 타입의 키만 설정(keyof) function getProperty<T, O extends keyof T>(obj: T, key: O) { return obj[key]; } const obj = { a: 1, b: 2, c: 3 }; getProperty(obj, 'a'); // -> OK getProperty(obj, 'z'); // -> 해당하는 속성 없음
- 타입을 따로 지정하지 않아도 변수 선언/초기화, 인자 기본값, 함수 반환값 등 설정할 때 타입 추론 발생
- Duck Typing 또는 Structural Subtyping 지향 : 값의 형태에 기반하는 추론
- [방식1] Best Common Type: 작성된 표현식 기준으로 가장 근접한 타입으로 추론하는 알고리즘
- [방식2] Contextual Typing: 코드상의 문맥을 기준으로 추론하는 알고리즘
// 함수의 타입 추론하기 위해 window.onmousedown의 타입 검사 => 마우스 이벤트와 연관이 있다는 추론 window.onmousedown = function(mouseEvent) { console.log(mouseEvent.button); // -> OK console.log(mouseEvent.kangaroo); // -> 해당하는 속성 없음 };// 함수의 타입 추론하기 위해 window.onscroll의 타입 검사 => 파라미터 uiEvent는 UIEvent 객체로 추론 window.onscroll = function(uiEvent) { console.log(uiEvent.button); // -> 해당하는 속성 없음 } // but 변수에 할당시 타입 추론이 어렵기 때문에 오류 미발생 // (tsconfig.json 파일에 noImplicitAny:false 설정시 오류 발생) const handler = function(uiEvent) { console.log(uiEvent.button); // -> **OK** }
- 개발자가 직접 타입 지정 캐스팅
as키워드 이용/* DOM API 조작할 때 많이 사용 */ const div = document.querySelector('div') as HTMLDivElement; div.innerText;
- 여러 타입 중 원하는 타입으로 좁혀내기
- [방식1]
typeof,instanceof연산자 이용// type Age = 'string' | 'number' function getAge(age: Age) { age.length; // 에러 발생 if (typeof age === 'string') { age.length; // 정상 동작 } } - [방식2] 커스텀 타입 가드 함수 이용 - 여러 객체 타입을 하나로 좁힐때 효과적
// type Age = 'string' | 'number' function isString(age: string | number):age is string { return typeof age === 'string'; } function getAge(age: Age) { age.length; // 에러 발생 if (isString(age)) { age.length; // 정상 동작 } }
- 구조적 타이핑(structural typing) 에 따라 구조적인 관점에서 동일한 속성 있는 경우 타입 호환
← JS: 기본적으로 객체 리터럴이나 익명함수 등을 사용
- 구조적 크기가 큰 인터페이스/클래스에 할당하는 경우 호환 OK
let capt = { name: "Captain", location: "Pangyo", }; interface Avengers { name: string; } let hero: Avengers; hero = capt; // 가능 <-name 속성 function assemble(a: Avengers) { console.log("어벤져스 모여라", a.name); } assemble(capt); // 가능 <-name 속성 interface Basecamp { name: string; type: string; } let base: Basecamp; // base = capt; // 불가능 <-type 속성
- 구조적 크기가 큰 인터페이스/클래스에 할당하는 경우 호환 OK
- Enum 타입 호환 : Number 타입과는 호환되지만, Enum끼리는 호환되지 않음
- Class 타입 호환 : 속성만 비교 / 스태틱 멤버(static member), 생성자 제외
- Generic 타입 호환 : 가 속성에 할당된 경우 타입 비교
interface Empty<T> { // 빈 로직 } const empty1: Empty<string>; const empty2: Empty<number>; empty1 = empty2; empty2 = empty1; // --==>> 호환에 문제 없음 interface NotEmpty<T> { data: T; } const notEmpty1: NotEmpty<string>; const notEmpty2: NotEmpty<number>; // notEmpty1 = notEmpty2; // notEmpty2 = notEmpty1; // --==>> 호환 불가능 - 컴파일 시점에 타입 추론 불가능한 경우 일단 안전하다고 보는 특성이 있음
- Soundness
들리지 않는다(it is said to not be sound)
- Soundness
- 자바스크립트 ES6+ Modules와 비슷 : 자체 유효 범위를 가지며, import/export 키워드 사용 필요
- cf. 자바스크립트 ES6 이전: asynchronous module definition(AMD), CommonJS 등 모듈 시스템 사용
-- types.ts export interface Todo { title: string; checked: boolean; }-- apps.ts import { Todo } from './types'; const item: Todo = { title; '오늘의 할 일', checked: false, }