diff --git a/class-note/10_type-assertion.ts b/class-note/10_type-assertion.ts
new file mode 100644
index 00000000..04119cba
--- /dev/null
+++ b/class-note/10_type-assertion.ts
@@ -0,0 +1,13 @@
+// 타입 단언(type assertion)
+var a;
+a = 20;
+a = 'a'
+var b = a as string;
+
+// DOM API 조작
+//
hi
+
+var div = document.querySelector('div');
+if (div) {
+ div.innerText
+}
\ No newline at end of file
diff --git a/class-note/11_type-guard.ts b/class-note/11_type-guard.ts
new file mode 100644
index 00000000..23c25116
--- /dev/null
+++ b/class-note/11_type-guard.ts
@@ -0,0 +1,34 @@
+interface Developer {
+ name: string;
+ skill: string;
+}
+
+interface Person {
+ name: string;
+ age: number;
+}
+
+function introduce(): Developer | Person {
+ return { name: 'Tony', age: 33, skill: 'Iron Making' }
+}
+var tony = introduce();
+console.log(tony.skill);
+
+if ((tony as Developer).skill) {
+ var skill = (tony as Developer).skill;
+ console.log(skill);
+} else if ((tony as Person).age) {
+ var age = (tony as Person).age;
+ console.log(age);
+}
+
+// 타입 가드 정의
+function isDeveloper(target: Developer | Person): target is Developer {
+ return (target as Developer).skill !== undefined;
+}
+
+if (isDeveloper(tony)) {
+ console.log(tony.skill);
+} else {
+ console.log(tony.age);
+}
\ No newline at end of file
diff --git a/class-note/12_type-compatibility.ts b/class-note/12_type-compatibility.ts
new file mode 100644
index 00000000..1e07d5e7
--- /dev/null
+++ b/class-note/12_type-compatibility.ts
@@ -0,0 +1,45 @@
+// 인터페이스
+interface Developer {
+ name: string;
+ skill: string;
+}
+// interface Person {
+// name: string;
+// // skill: string;
+// }
+class Person {
+ name: string;
+ skill: string;
+}
+
+var developer: Developer;
+var person: Person;
+developer = new Person();
+// person = developer;
+
+// 함수
+var add = function(a: number) {
+ // ...
+}
+var sum = function(a: number, b: number) {
+ // ...
+}
+sum = add;
+// add = sum;
+
+// 제네릭
+interface Empty {
+ // ..
+}
+var empty1: Empty;
+var empty2: Empty;
+empty1 = empty2;
+empty2 = empty1;
+
+interface NotEmpty {
+ data: T;
+}
+var notempty1: NotEmpty;
+var notempty2: NotEmpty;
+notempty1 = notempty2;
+notempty2 = notempty1;
\ No newline at end of file
diff --git a/class-note/13_utility-type.ts b/class-note/13_utility-type.ts
new file mode 100644
index 00000000..f2453439
--- /dev/null
+++ b/class-note/13_utility-type.ts
@@ -0,0 +1,72 @@
+interface Product {
+ id: number;
+ name: string;
+ price: number;
+ brand: string;
+ stock: number;
+}
+
+// 1. 상품 목록을 받아오기 위한 API 함수
+function fetchProducts(): Promise {
+ // ..
+}
+
+// interface ProductDetail {
+// id: number;
+// name: string;
+// price: number;
+// }
+
+// 2. 특정 상품의 상세 정보를 나타내기 위한 함수
+type ShoppingItem = Pick
+function displayProductDetail(shoppingItem: Pick) {
+
+}
+
+// interface UpdateProduct {
+// id?: number;
+// name?: string;
+// price?: number;
+// brand?: string;
+// stock?: number;
+// }
+
+type UpdateProduct = Partial
+// 3. 특정 상품 정보를 업데이트(갱신)하는 함수
+function updateProductItem(productItem: Partial) {
+
+}
+
+// 4. 유틸리티 타입 구현하기 - Partial
+interface UserProfile {
+ username: string;
+ email: string;
+ profilePhotoUrl: string;
+}
+// interface UserProfileUpdate {
+// username?: string;
+// email?: string;
+// profilePhotoUrl?: string;
+// }
+// #1
+// type UserProfileUpdate = {
+// username?: UserProfile['username'];
+// email?: UserProfile['email'];
+// profilePhotoUrl?: UserProfile['profilePhotoUrl'];
+// }
+
+// #2
+type UserProfileUpdate = {
+ [p in 'username' | 'email' | 'profilePhotoUrl']?: UserProfile[p]
+}
+type UserProfileKeys = keyof UserProfile
+
+// #3
+type UserProfileUpdate = {
+ [p in keyof UserProfile]?: UserProfile[p]
+}
+
+// #4
+type Subset = {
+ [p in keyof T]?: T[p]
+}
diff --git a/class-note/14_mapped-type.ts b/class-note/14_mapped-type.ts
new file mode 100644
index 00000000..208ac938
--- /dev/null
+++ b/class-note/14_mapped-type.ts
@@ -0,0 +1,13 @@
+type Heroes = 'Hulk' | 'Capt' | 'Thor'
+type HeroAges = { [K in Heroes]: number }
+const ages: HeroAges = {
+ Hulk: 33,
+ Capt: 100,
+ Thor: 1000,
+}
+
+// for in 반복문 코드
+// var arr = ['a','b','c'];
+// for (var key in arr) {
+// console.log(arr[key]);
+// }
\ No newline at end of file
diff --git a/class-note/1_type-basic.ts b/class-note/1_type-basic.ts
new file mode 100644
index 00000000..304569ee
--- /dev/null
+++ b/class-note/1_type-basic.ts
@@ -0,0 +1,30 @@
+// JS 문자열 선언
+// var str = 'hello';
+
+// TS 문자열 선언
+let str: string = 'hello';
+
+// TS 숫자
+let num: number = 10;
+
+// TS 배열
+let arr: Array = [1,2,3];
+let heroes: Array = ['Capt', 'Thor', 'Hulk', 10]
+let items: number[] = [1,2,3];
+
+// TS 튜플
+let address: [string, number] = ['gangnam', 100];
+
+// TS 객체
+let obj: object = {};
+// let person: object = {
+// name: 'capt',
+// age: 100
+// };
+let person: { name: string, age: number } = {
+ name: 'thor',
+ age: 1000
+}
+
+// TS 진위값
+let show: boolean = true;
\ No newline at end of file
diff --git a/class-note/2_functions.ts b/class-note/2_functions.ts
new file mode 100644
index 00000000..aa44133b
--- /dev/null
+++ b/class-note/2_functions.ts
@@ -0,0 +1,23 @@
+// 함수의 파라미터에 타입을 정의하는 방식
+// function sum(a: number, b: number) {
+// return a + b;
+// }
+// sum(10, 20);
+
+// 함수의 반환 값에 타입을 정의하는 방식
+function add(): number {
+ return 10;
+}
+
+// 함수에 타입을 정의하는 방식
+function sum(a: number, b: number): number {
+ return a + b;
+}
+sum(10);
+
+// 함수의 옵셔널 파라미터(?)
+function log(a: string, b?: string) {
+
+}
+log('hello world');
+log('hello ts', 'abc');
\ No newline at end of file
diff --git a/class-note/3_interface.ts b/class-note/3_interface.ts
new file mode 100644
index 00000000..24c6e99e
--- /dev/null
+++ b/class-note/3_interface.ts
@@ -0,0 +1,68 @@
+interface User {
+ age: number;
+ name: string;
+}
+
+// 변수에 인터페이스 활용
+var seho: User = {
+ age: 33,
+ name: '세호'
+}
+
+// 함수에 인터페이스 활용
+function getUser(user: User) {
+ console.log(user);
+}
+const capt = {
+ name: '캡틴',
+ age: 100
+}
+getUser(capt);
+
+// 함수의 스펙(구조)에 인터페이스를 활용
+interface SumFunction {
+ (a: number, b: number): number;
+}
+
+var sum: SumFunction;
+sum = function(a: number, b: number): number {
+ return a + b;
+}
+
+// 인덱싱
+interface StringArray {
+ [index: number]: string;
+}
+
+var arr: StringArray = ['a','b','c'];
+// arr[0] = 10;
+
+// 딕셔너리 패턴
+interface StringRegexDictionary {
+ [key: string]: RegExp;
+}
+
+var obj: StringRegexDictionary = {
+ // sth: /abc/,
+ cssFile: /\.css$/,
+ jsFile: /\.js$/,
+}
+// obj['cssFile'] = 'a'
+
+Object.keys(obj).forEach(function(value) {});
+
+// 인터페이스 확장
+interface Person {
+ name: string;
+ age: number;
+}
+
+interface Developer extends Person {
+ language: string;
+}
+
+var captain: Developer = {
+ language: 'ts',
+ age: 100,
+ name: '캡틴'
+}
\ No newline at end of file
diff --git a/class-note/4_type-aliases.ts b/class-note/4_type-aliases.ts
new file mode 100644
index 00000000..5e57a307
--- /dev/null
+++ b/class-note/4_type-aliases.ts
@@ -0,0 +1,22 @@
+// interface Person {
+// name: string;
+// age: number;
+// }
+
+type Person = {
+ name: string;
+ age: number;
+}
+
+var seho: Person = {
+ name: '세호',
+ age: 30
+}
+
+type MyString = string;
+var str: MyString = 'hello';
+
+type Todo = { id: string; title: string; done: boolean };
+function getTodo(todo: Todo) {
+
+}
\ No newline at end of file
diff --git a/class-note/5_operator.ts b/class-note/5_operator.ts
new file mode 100644
index 00000000..9c60ed30
--- /dev/null
+++ b/class-note/5_operator.ts
@@ -0,0 +1,35 @@
+// function logMessage(value: any) {
+// console.log(value);
+// }
+// logMessage('hello');
+// logMessage(100);
+
+var seho: string | number | boolean;
+function logMessage(value: string | number) {
+ if (typeof value === 'number') {
+ value.toLocaleString();
+ }
+ if (typeof value === 'string') {
+ value.toString();
+ }
+ throw new TypeError('value must be string or number');
+}
+logMessage('hello');
+logMessage(100);
+
+// 인터섹션(교차) 타입
+interface Developer {
+ name: string;
+ skill: string;
+}
+
+interface Person {
+ name: string;
+ age: number;
+}
+
+function askSomeone(someone: Developer & Person) {
+ someone.name;
+ someone.age;
+ someone.skill;
+}
\ No newline at end of file
diff --git a/class-note/6_enum.ts b/class-note/6_enum.ts
new file mode 100644
index 00000000..0edff431
--- /dev/null
+++ b/class-note/6_enum.ts
@@ -0,0 +1,27 @@
+enum Shoes {
+ Nike = '나이키',
+ Adidas = '아디다스'
+}
+
+var myShoes = Shoes.Nike;
+console.log(myShoes); // '나이키'
+
+// 예제
+enum Answer {
+ Yes = 'Y',
+ No = 'N',
+}
+
+function askQuestion(answer: Answer) {
+ if (answer === Answer.Yes) {
+ console.log('정답입니다');
+ }
+ if (answer === Answer.No) {
+ console.log('오답입니다');
+ }
+}
+askQuestion(Answer.Yes);
+askQuestion('Yes');
+// askQuestion('예스');
+// askQuestion('y');
+// askQuestion('Yes');
\ No newline at end of file
diff --git a/class-note/7_class.ts b/class-note/7_class.ts
new file mode 100644
index 00000000..a6e4fd9a
--- /dev/null
+++ b/class-note/7_class.ts
@@ -0,0 +1,28 @@
+class Person {
+ private name: string;
+ public age: number;
+ readonly log: string;
+
+ constructor(name: string, age: number) {
+ this.name = name;
+ this.age = age;
+ }
+}
+
+// 리액트 예전 문법 - 클래스 기반 코드
+class App extends React.Component {
+
+}
+
+// 리액트 최신 문법 - 훅 기반의 함수형 코드
+function App() {
+ return
Hello World
+}
+
+//
+new Vue({
+ el: '',
+ setup() {
+
+ }
+})
\ No newline at end of file
diff --git a/class-note/8_generics.ts b/class-note/8_generics.ts
new file mode 100644
index 00000000..2d02a481
--- /dev/null
+++ b/class-note/8_generics.ts
@@ -0,0 +1,95 @@
+// function logText(text) {
+// console.log(text);
+// return text;
+// }
+// logText(10); // 숫자 10
+// logText('하이'); // 문자열 하이
+// logText(true); // 진위값 true
+
+// function logText(text: T): T {
+// console.log(text);
+// return text;
+// }
+// logText('하이');
+
+// function logText(text: string) {
+// console.log(text);
+// // text.split('').reverse().join('');
+// return text;
+// }
+
+// function logNumber(num: number) {
+// console.log(num);
+// return num;
+// }
+
+// function logText(text: string | number) {
+// console.log(text);
+// return text;
+// }
+
+// const a = logText('a');
+// logText(10);
+// const num = logNumber(10);
+// logText(true);
+
+function logText(text: T): T {
+ console.log(text);
+ return text;
+}
+
+// const str = logText('abc');
+// str.split('');
+// const login = logText(true);
+
+// logText('a')
+// logText(10)
+
+// 인터페이스에 제네릭을 선언하는 방법
+// interface Dropdown {
+// value: string;
+// selected: boolean;
+// }
+
+// const obj: Dropdown = { value: 'abc', selected: false };
+
+interface Dropdown {
+ value: T;
+ selected: boolean;
+}
+const obj: Dropdown = { value: 'abc', selected: false };
+
+// 제네릭 타입 제한
+// function logTextLength(text: T[]): T[] {
+// console.log(text.length);
+// text.forEach(function (text) {
+// console.log(text);
+// });
+// return text;
+// }
+// logTextLength(['hi', 'abc']);
+
+// 제네릭 타입 제한 2 - 정의된 타입 이용하기
+interface LengthType {
+ length: number;
+}
+function logTextLength(text: T): T {
+ text.length;
+ return text;
+}
+logTextLength(10);
+logTextLength({ leng: 10 });
+
+// 제네릭 타입 제한 3 - keyof
+interface ShoppingItem {
+ name: string;
+ price: number;
+ stock: number;
+}
+
+function getShoppingItemOption(itemOption: T): T {
+ return itemOption;
+}
+// getShoppingItemOption(10);
+// getShoppingItemOption('a');
+getShoppingItemOption('name');
diff --git a/class-note/9_type-inference.ts b/class-note/9_type-inference.ts
new file mode 100644
index 00000000..3a12f99f
--- /dev/null
+++ b/class-note/9_type-inference.ts
@@ -0,0 +1,39 @@
+// 타입 추론 기본 1
+var a = 'abc';
+
+function getB(b = 10) {
+ var c = 'hi';
+ return b + c;
+}
+
+10 + '10'; // 1010
+
+// 타입 추론 기본 2
+// interface Dropdown {
+// value: T;
+// title: string;
+// }
+// var shoppingItem: Dropdown = {
+// value: 'abc',
+// title: 'hello'
+// }
+
+// 타입 추론 기본 3
+interface Dropdown {
+ value: T;
+ title: string;
+}
+interface DetailedDropdown extends Dropdown {
+ description: string;
+ tag: K;
+}
+
+var detailedItem: DetailedDropdown = {
+ title: 'abc',
+ description: 'ab',
+ value: 'a',
+ tag: 'a',
+};
+
+// Best Common Type
+var arr = [1, 2, true, true, 'a'];
diff --git a/class-note/class.js b/class-note/class.js
new file mode 100644
index 00000000..54e4df44
--- /dev/null
+++ b/class-note/class.js
@@ -0,0 +1,17 @@
+function Person(name, age) {
+ this.name = name;
+ this.age = age;
+}
+var capt = new Person('캡틴', 100);
+
+class Person {
+ // 클래스 로직
+ constructor(name, age) {
+ console.log('생성 되었습니다');
+ this.name = name;
+ this.age = age;
+ }
+}
+
+var seho = new Person('세호', 30); // 생성 되었습니다.
+console.log(seho);
\ No newline at end of file
diff --git a/class-note/function.js b/class-note/function.js
new file mode 100644
index 00000000..03607ad4
--- /dev/null
+++ b/class-note/function.js
@@ -0,0 +1,5 @@
+function sum(a, b) {
+ return a + b;
+}
+
+sum(10, 20, 30, 40, 50);
\ No newline at end of file
diff --git a/class-note/ts-modules/app.ts b/class-note/ts-modules/app.ts
new file mode 100644
index 00000000..fb21cc25
--- /dev/null
+++ b/class-note/ts-modules/app.ts
@@ -0,0 +1,6 @@
+import { Todo } from './types'
+
+var item: Todo = {
+ title: '할 일 1',
+ checked: false,
+}
\ No newline at end of file
diff --git a/class-note/ts-modules/types.ts b/class-note/ts-modules/types.ts
new file mode 100644
index 00000000..338f2d89
--- /dev/null
+++ b/class-note/ts-modules/types.ts
@@ -0,0 +1,4 @@
+export interface Todo {
+ title: string;
+ checked: boolean;
+}
diff --git a/es6/arrow-function.js b/es6/arrow-function.js
new file mode 100644
index 00000000..593e230f
--- /dev/null
+++ b/es6/arrow-function.js
@@ -0,0 +1,19 @@
+// ES5 - 함수 선언문
+function sum(a, b) {
+ return a + b;
+}
+// ES5 - 함수 표현식
+var sum = function(a, b) {
+ return a + b;
+}
+
+// ES6+ - 함수 표현식(화살표 함수)
+var sum = (a, b) => {
+ return a + b;
+}
+var sum = (a, b) => a + b;
+
+// 타입스크립트의 화살표 함수
+var sum = (a: number, b: number): number => {
+ return a + b;
+}
\ No newline at end of file
diff --git a/example/4_interfaces.ts b/example/4_interfaces.ts
index bf087215..7a753d14 100644
--- a/example/4_interfaces.ts
+++ b/example/4_interfaces.ts
@@ -5,7 +5,7 @@ interface User {
}
// 변수에 사용하는 경우
-const seho: User = { name: 'hi', age: 100 };
+const seho: User = { name: '세호', age: 100 };
// 함수의 매개변수에 사용하는 경우
function getUser(user: User) {
@@ -14,21 +14,34 @@ function getUser(user: User) {
getUser(seho);
// 함수의 전체 타입에 사용하는 경우
-// interface SumFunction {
-// (a: number, b: number): number;
-// }
-// let sum: SumFunction;
-// sum = function (num1: number, num2: string): number {
-// return num1 + num2;
-// };
+interface SumFunction {
+ (a: number, b: number): number;
+}
+let sum: SumFunction;
+sum = function (num1: number, num2: string): number {
+ return num1 + num2;
+};
// 배열의 인덱싱에 사용하는 경우
-// interface StringArray {
-// [index: number]: string;
-// }
-// let arr: StringArray;
-// arr[0] = 'hi';
-// arr[1] = 10;
+interface StringArray {
+ [index: number]: string;
+}
+let arr: StringArray;
+arr[0] = 'hi';
+arr[1] = 10;
+
+// 딕셔너리 패턴
+interface StringRegexDictionary {
+ [key: string]: RegExp;
+}
+
+const regexMap: StringRegexDictionary = {
+ cssFile: /\.css$/,
+ jsFile: /\.js$/,
+};
+
+Object.keys(regexMap).forEach(function(value) {
+})
// 인터페이스 확장
interface Person {
diff --git a/example/7_union-intersection.ts b/example/7_union-intersection.ts
index 47dcd1ca..171e3c20 100644
--- a/example/7_union-intersection.ts
+++ b/example/7_union-intersection.ts
@@ -37,4 +37,4 @@ interface Person {
function askSomeone(someone: Developer | Person) {
someone.name; // O
someone.age; // X
-}
\ No newline at end of file
+}
diff --git a/example/8_generics.ts b/example/8_generics.ts
index 636bc786..c98f24da 100644
--- a/example/8_generics.ts
+++ b/example/8_generics.ts
@@ -39,15 +39,16 @@ interface ShoppingItems {
stock: number;
}
function getAllowedOptions(option: T): T {
- if (option === 'name' || option === 'address') {
- console.log('option type is string');
- return option;
- }
- if (option === 'price' || option === 'stock') {
- console.log('option type is number');
- return option;
- }
+ return option;
+ // if (option === 'name' || option === 'address') {
+ // console.log('option type is string');
+ // return option;
+ // }
+ // if (option === 'price' || option === 'stock') {
+ // console.log('option type is number');
+ // return option;
+ // }
}
getAllowedOptions('nothing');
// const a = getAllowedOptions('name');
-// a.toUpperCase(); // Name
\ No newline at end of file
+// a.toUpperCase(); // Name
diff --git a/example/9_type-inference.ts b/example/9_type-inference.ts
new file mode 100644
index 00000000..9e47543c
--- /dev/null
+++ b/example/9_type-inference.ts
@@ -0,0 +1,26 @@
+var a = 'a';
+
+function logA(a = 'a') {
+ var b = 10;
+ return b;
+}
+
+interface Dropdown {
+ value: T
+ title: string;
+}
+var items: Dropdown = {
+ value: 10,
+ title: 'a'
+}
+
+interface DetailedDropdown extends Dropdown {
+ description: string;
+ tag: T;
+}
+var detailItems: DetailedDropdown = {
+ value: 'hi',
+ title: 'a',
+ description: 'b',
+ tag: 'c'
+}
\ No newline at end of file
diff --git a/example/dropdown-generic.html b/example/dropdown-generic.html
new file mode 100644
index 00000000..a21297b0
--- /dev/null
+++ b/example/dropdown-generic.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ Document
+
+
+
+
이메일 선택 드롭다운
+
+
+
+
상품 수량 선택 드롭다운
+
+
+
+
diff --git a/example/dropdown-generic.ts b/example/dropdown-generic.ts
new file mode 100644
index 00000000..fbca5888
--- /dev/null
+++ b/example/dropdown-generic.ts
@@ -0,0 +1,50 @@
+interface DropdownItem {
+ value: T;
+ selected: boolean;
+}
+
+// interface Email {
+// value: string;
+// selected: boolean;
+// }
+
+const emails: DropdownItem[] = [
+ { value: 'naver.com', selected: true },
+ { value: 'gmail.com', selected: false },
+ { value: 'hanmail.net', selected: false },
+];
+
+// interface ProductNumber {
+// value: number;
+// selected: boolean;
+// }
+
+// interface TrueFalse {
+// value: boolean;
+// selected: boolean;
+// }
+
+const numberOfProducts: DropdownItem[] = [
+ { value: 1, selected: true },
+ { value: 2, selected: false },
+ { value: 3, selected: false },
+];
+
+function createDropdownItem(item: DropdownItem | DropdownItem) {
+ const option = document.createElement('option');
+ option.value = item.value.toString();
+ option.innerText = item.value.toString();
+ option.selected = item.selected;
+ return option;
+}
+
+// NOTE: 이메일 드롭 다운 아이템 추가
+emails.forEach(function (email) {
+ const item = createDropdownItem(email);
+ const selectTag = document.querySelector('#email-dropdown');
+ selectTag.appendChild(item);
+});
+
+numberOfProducts.forEach(function (product) {
+ const item = createDropdownItem(product);
+});
diff --git a/example/type-comp.ts b/example/type-comp.ts
new file mode 100644
index 00000000..73156855
--- /dev/null
+++ b/example/type-comp.ts
@@ -0,0 +1,30 @@
+// 인터페이스
+interface Developer {
+ name: string;
+ skill: string;
+}
+
+interface Person {
+ name: string;
+}
+
+var a: Developer;
+var b: Person;
+// a = b; // X
+b = a; // O
+
+// 함수
+var add = function(a: number) {
+ // ...
+}
+var sum = function(a: number, b: number) {
+ // ...
+}
+// sum = add; // X
+// add = sum; // O
+
+// // 유니온 타입
+// var c: Developer | Person;
+// var d: Person | string;
+// c = d;
+// d = c;
\ No newline at end of file
diff --git a/getting-started/index.js b/getting-started/index.js
new file mode 100644
index 00000000..7353c52e
--- /dev/null
+++ b/getting-started/index.js
@@ -0,0 +1,4 @@
+function sum(a, b) {
+ return a + b;
+}
+sum(10, 20);
diff --git a/getting-started/index.ts b/getting-started/index.ts
new file mode 100644
index 00000000..b61aa437
--- /dev/null
+++ b/getting-started/index.ts
@@ -0,0 +1,5 @@
+function sum(a: number, b: number): number {
+ return a + b;
+}
+
+sum(10, 20);
diff --git a/getting-started/tsconfig.json b/getting-started/tsconfig.json
new file mode 100644
index 00000000..245154fb
--- /dev/null
+++ b/getting-started/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "compilerOptions": {
+ "allowJs": true,
+ "checkJs": true,
+ "noImplicitAny": true
+ }
+}
diff --git a/project/.eslintignore b/project/.eslintignore
new file mode 100644
index 00000000..76add878
--- /dev/null
+++ b/project/.eslintignore
@@ -0,0 +1,2 @@
+node_modules
+dist
\ No newline at end of file
diff --git a/project/.eslintrc.js b/project/.eslintrc.js
new file mode 100644
index 00000000..a900b4b7
--- /dev/null
+++ b/project/.eslintrc.js
@@ -0,0 +1,31 @@
+// .eslintrc.js
+module.exports = {
+ root: true,
+ env: {
+ browser: true,
+ node: true,
+ },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/eslint-recommended',
+ 'plugin:@typescript-eslint/recommended',
+ ],
+ plugins: ['prettier', '@typescript-eslint'],
+ rules: {
+ 'prettier/prettier': [
+ 'error',
+ {
+ singleQuote: true,
+ semi: true,
+ useTabs: false,
+ tabWidth: 2,
+ printWidth: 80,
+ bracketSpacing: true,
+ arrowParens: 'avoid',
+ },
+ ],
+ },
+ parserOptions: {
+ parser: '@typescript-eslint/parser',
+ },
+};
diff --git a/project/README.md b/project/README.md
index b3ba8aa8..91f35ac1 100644
--- a/project/README.md
+++ b/project/README.md
@@ -2,6 +2,22 @@
최종 프로젝트 폴더입니다
+## 자바스크립트 프로젝트에 타입스크립트 적용하기
+
+0. 자바스크립트 파일에 JSDoc으로 타입 시스템 입히기
+1. 타입스크립트의 기본 환경 구성
+ - [x] NPM 초기화
+ - [x] 타입스크립트 라이브러리 설치
+ - [x] 타입스크립트 설정 파일 생성 및 기본 값 추가
+ - [x] 자바스크립트 파일을 타입스크립트 파일로 변환
+ - [x] `tsc` 명령어로 타입스크립트 컴파일 하기
+2. 명시적인 `any` 선언하기
+ - `tsconfig.json` 파일에 `noImplicitAny` 값을 `true`로 추가
+ - 가능한한 구체적인 타입으로 타입 정의
+3. 프로젝트 환경 구성
+ - babel, eslint, prettier 등의 환경 설정
+4. 외부 라이브러리 모듈화
+
## 참고 자료
- [존스 홉킨스 코로나 현황](https://www.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6)
diff --git a/project/index.html b/project/index.html
index 90d0ae59..d412b905 100644
--- a/project/index.html
+++ b/project/index.html
@@ -54,6 +54,6 @@