diff --git a/dist/app.js b/dist/app.js index 2d982eb..fa5b1c1 100644 --- a/dist/app.js +++ b/dist/app.js @@ -1,26 +1,31 @@ "use strict"; -// const ADMIN = 0; -// const READ_ONLY = 1; -// const AUTHOR = 2; -var Role; -(function (Role) { - Role[Role["ADMIN"] = 0] = "ADMIN"; - Role[Role["READ_ONLY"] = 1] = "READ_ONLY"; - Role[Role["AUTHOR"] = 2] = "AUTHOR"; -})(Role || (Role = {})); -var person = { - name: 'Maximilian', - age: 30, - hobbies: ['Sports', 'Cooking'], - role: Role.ADMIN, //0 -}; -person.role = Role.READ_ONLY; -if (person.role === Role.ADMIN) { - console.log(person.role); -} -else if (person.role === Role.READ_ONLY) { - console.log(person.role); -} -else if (person.role === Role.AUTHOR) { - console.log(person.role); -} +var Department = /** @class */ (function () { + // readonly는 프로퍼티를 초기화한 후 수정할 수 없다. 즉, 한번 할당 되면 변경되면 안되는 고유 번호들을 설정할 때 readonly를 사용한다. + function Department(id, name) { + this.id = id; + this.name = name; + // private id: string; + // private name: string; + this.employees = []; + // this.id = id; + // this.name = n + } + Department.prototype.describe = function () { + console.log("Department (".concat(this.id, "): ").concat(this.name)); + }; + Department.prototype.addEmployee = function (employee) { + // this.id = '2'; // readonly이기 때문에 error가 발생한다. + this.employees.push(employee); + }; + Department.prototype.printEmployeeInformation = function () { + console.log(this.employees.length); + console.log(this.employees); + }; + return Department; +}()); +var accounting = new Department('1', 'Accounting'); +accounting.addEmployee('Max'); +accounting.addEmployee('Manu'); +// accounting.employees[2] = 'Anna'; +accounting.describe(); +accounting.printEmployeeInformation(); diff --git a/dist/basics.js b/dist/basics.js deleted file mode 100644 index badc6c2..0000000 --- a/dist/basics.js +++ /dev/null @@ -1,16 +0,0 @@ -"use strict"; -function add(n1, n2, showResult, phrase) { - var result = n1 + n2; //result는 number라고 추론을 한다. - if (showResult) { - console.log(result + phrase); - } - else { - return n1 + n2; - } -} -var number1 = 5; -var number2 = 2.8; -var printResult = true; -var resultPhrase = 'Result is: '; -// resultPhrase = 0; //error -> 타입 추론으로 resultPhrase는 string이다. 따라 0이라는 number타입을 할당할 수 없다. -add(number1, number2, printResult, resultPhrase); diff --git a/package.json b/package.json index d8e39e3..0d16423 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", + "watch": "tsc -w", "start": "ts-node src/app.ts", "build": "tsc --build", "clean": "tsc --build --clean" @@ -15,4 +16,4 @@ "ts-node": "^10.9.2", "typescript": "^5.5.4" } -} +} \ No newline at end of file diff --git a/src/app.js b/src/app.js deleted file mode 100644 index a0d2b94..0000000 --- a/src/app.js +++ /dev/null @@ -1,24 +0,0 @@ -//항상 유니온 타입을 지정하는 것은 많이 번거롭다. 이에 alias 타입으로 사용자 지정 타입을 정할 수 있다. 즉, 타입을 우리가 다로 별칭으로 만들어 낼 수 있다. -function combine(n1, n2, resultConversion) { - var result; - if (typeof n1 === 'number' && typeof n2 === 'number' || resultConversion === 'as-number') { - result = +n1 + +n2; - } - else if (typeof n1 === 'string' && typeof n2 === 'string') { - result = n1 + n2; - } - else { - result = n1.toString() + n2.toString(); - } - // if (resultConversion === 'as-number') { - // return +result; - // } else { - // return result.toString(); - // } -} -var combineAges = combine(20, 30, 'as-number'); -console.log(combineAges); -var combinedStringAges = combine('20', '30', 'as-number'); -console.log(combinedStringAges); -var combineNames = combine('Max', 'Anna', 'as-text'); -console.log(combineNames); diff --git a/src/app.ts b/src/app.ts index 00ce4bd..f9a16f9 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,21 +1,75 @@ -let userInput: unknown; +interface Named { + readonly name: string; +} + +// interface는 객체의 구조를 정의하는데 사용된다.(각 객체들의 Type 명세서) +/* type 함수 커스텀 방식 */ +// type AddFn = (a: number, b: number) => number; + +// let add: AddFn; + +// add = (n1: number, n2: number) => { +// return n1 + n2; +// } -let userName: string; -userInput = 5; -userInput = 'Max'; +/* interface 함수 커스텀 방식 */ +// 사실 여기선 type 커스텀 방식을 사용하는 것이 일반적이다. -console.log(typeof userInput); +interface AddFn { //익명함수 + (a: number, b: number): number; +} + +interface GreetAble extends Named { + greet(phrase: string): void; +} -if (typeof userInput === 'string') { - userName = userInput; +class Person implements GreetAble { + name: string; + age: number; + constructor(n: string, N: number) { + this.name = n; + this.age = N; + } + greet(phrase: string): void { + console.log(phrase + ' ' + this.name); + } } -function generateError(message: string, code: number): never { //:never - throw { message: message, errorCode: code }; -} //generateError는 never타입을 반환한다. 이유는 throw 때문인데 절대적으로 값이 변하면 안되기 때문이다. 따라서 never타입은 다음과 같다. -//never 타입은 어떠한 값도 반환하지 않는 함수의 반환 타입을 나타낸다. 이 타입은 함수가 정상적으로 완료되지 않고 항상 예외를 던지거나 무한 루프에 빠져 끝나지 않는 경우에 사용된다. 오해하지 말아야할 것은 literal type으로 확인을 하면 void로 선언이 되어있지만 throw를 사용하면 무조건으로 never가 반환된다. 따라서 암묵적으로 never를 반환은 하지만 never타입임을 코드에 명시해주는 것이 좋다. +// custom function type과 interface function의 차이 +// 함수 타입 커스텀 방식과 인터페이스에서 함수 정의는 모두 함수의 타입을 명시하는 방법이다. 이 두 방식은 서로 유사해 보이지만 사용 목적과 적절한 상황에 따라 선택해야 한다. + +//custom function type +// 타입 별칭(type)을 사용해서 함수를 정의하는 방식은 단순한 함수 시그니처를 정의할 때 주로 사용된다. 함수의 인자와 반환 타입을 정의하고 이를 타입으로 재사용할 수 있다. +// * 적절한 사용 시기: +// 단순한 함수의 시그니처를 정의하고 싶을 때 적합 +// 객체 형태가 아닌 독립적인 함수 타입을 정의해야 할 때 유용 +// 함수가 단순한 인자와 반환 값만을 가지고 있고, 추가적인 속성이 필요하지 않은 경우에 좋다. +// * 필요 목적: +// 여러 함수가 동일한 시그니처를 가질 때 반복 없이 함수 타입을 정의할 수 있다. +// 함수 자체를 타입으로 처리할 때 유용합니다.예를 들어 고차 함수(재귀함수)에서 함수 타입을 인자로(event) 받을 때 명확하게 함수 시그니처를 지정할 수 있습니다. + +//interface function +// 인터페이스에서 함수를 정의하는 방식은 객체의 일부로 함수를 다룰 때 주로 사용된다. 인터페이스를 사용하여 구조적인 객체를 정의하고, 그 안에 함수를 포함시킬 수 있다. +// * 적절한 사용 시기: +// 함수가 객체의 일부로 정의될 때, 즉 속성, 메서드, 함수가 함께 복합적으로 존재하는 구조적 정의가 필요할 때 사용 +// 객체의 구조를 정의하면서 여러 메서드나 속성이 포함될 때 적합 +// * 필요 목적: +// 함수가 객체의 일부분으로 사용될 때, 속성이나 다른 메서드와 함께 관리할 수 있는 명확한 구조를 제공해야 할 때 +// 구조적 객체 설계를 강제하고 여러 메서드를 포함하는 객체의 형태를 명확히 정의해야 할 때 + + +let user1: GreetAble; + +user1 = new Person('Mike', 26); + +// user1 = { +// name: "Mike", +// age: 26, +// greet(phrase: string) { +// console.log(phrase + ' ' + this.name); +// } +// }; + +user1.greet('Hi there - I am'); -const resultError = generateError('An error occurred!', 500); -console.log('resultError: ', resultError); //본래 일반적인 함수라면 undefined를 반환해야한다. -//하지만 아무것도 반환되는 것이 없다. 이유는 generateError는 never 타입으로 반환이 되기 때문에 컴파일이 중도 정지가 되는 것이다. -//참고로 throw는 try,catch를 사용해도 무시하지 않고 중도 정지가 된다. \ No newline at end of file +console.log(user1); \ No newline at end of file diff --git a/src/basics.ts b/src/basics.ts deleted file mode 100644 index ceab1ff..0000000 --- a/src/basics.ts +++ /dev/null @@ -1,41 +0,0 @@ -function addTemplate(n1: number, n2: number, showResult: boolean, phrase: string) { - const result = n1 + n2; //result는 number라고 추론을 한다. - if (showResult) { - console.log(result + phrase); - } else { - return n1 + n2; - } -} - -const number1 = 5; -const number2 = 2.8; -const printResultTemp = true; -const resultPhrase = 'Result is: '; -// resultPhrase = 0; //error -> 타입 추론으로 resultPhrase는 string이다. 따라 0이라는 number타입을 할당할 수 없다. - -addTemplate(number1, number2, printResultTemp, resultPhrase); - -const person: { - name: string, - age: number, - hobbies: string[]; - role: (number | string)[]; -} = { - name: 'Maximilian', - age: 30, - hobbies: ['Sports', 'Cooking'], - role: [2, 'author'] -}; - -person.role.push('admin'); -person.role[1] = 10; -person.role = [0, 'admin', 'user']; - -let favoriteActivities: any[]; -favoriteActivities = ['Sports', 1]; - -console.log(person.name); - -for (const hobby of person.hobbies) { - console.log(hobby); -} diff --git a/src/classes.ts b/src/classes.ts new file mode 100644 index 0000000..e1bb2f6 --- /dev/null +++ b/src/classes.ts @@ -0,0 +1,123 @@ +abstract class Department { + // private id: string; + // private name: string; + //현재 Department는 추상클래스로 id가 다른 클래스에서도 사용 되어야해서 private에서 protected로 접근제한자를 변경 + protected employees: string[] = []; // employees 변경 + static fiscalYear = 2020; + // id 변경 + constructor(protected readonly id: string, public name: string) { + // this.id = id; + // this.name = n + // console.log(this.fiscalYear); + console.log(Department.fiscalYear); //정상동작 + } + static createEmployee(name: string) { + return { name: name }; + } + + //abstract인 추상 함수를 사용하라면 해당 class 또한 abstract로 정의 되어야 한다. + abstract describe(this: Department): void; //또한 해당 추상 함수에 어떠한 것도 정의되어 있으면 안된다. + //이제 Department와 연관된 모든 클래스들은 Error가 발생할 것이다. + // { + // console.log(`Department (${this.id}): ${this.name}`); + // } + + addEmployee(employee: string) { + // this.id = '2'; // readonly이기 때문에 error가 발생한다. + this.employees.push(employee); + } + + printEmployeeInformation() { + console.log(this.employees.length); + console.log(this.employees); + } +} +class ITDepartment extends Department { + admins: string[]; + constructor(id: string, admins: string[]) { + super(id, 'IT'); + this.admins = admins; + } + //추상함수 정의 + describe() { + console.log(`Department (${this.id}): ${this.name}`); + }; +} + +//현재 상황에서 회계관련 문서가 하나밖에 없다고 가정 +//따라서 private를 활용해야 한다. +class AccountingDepartment extends Department { + private lastReport: string; + private static instance: AccountingDepartment; + + get mostRecentReport() { + if (this.lastReport) { + return this.lastReport; + } + throw new Error('No report found.'); + } + + set setMostRecentReport(value: string) { + if (!value) { + throw new Error('Please pass in a valid value!') + } + this.addReport(value); + this.lastReport = value; + } + //접근제한자: private 부여 + private constructor(id: string, private reports: string[]) { + super(id, 'Account'); + this.lastReport = reports[0] || ""; + } + + static getInstance() { + //this.instance 또는 직접적으로 접근 + if (AccountingDepartment.instance) { //인스턴스가 없다면 new키워드로 새로운 인스턴스를 생성한다. 이를 통해 하나의 인스턴스로만 동작 + return this.instance; + } + + this.instance = new AccountingDepartment('d2', []); + return this.instance; + } + + describe() { + console.log(`Department (${this.id}): ${this.name}`); + }; + + addReport(text: string) { + this.reports.push(text); + } + + printReports() { + console.log(this.reports); + } +} + +// const accounting = new Department('1', 'Accounting'); //추상 클래스는 인스턴스할 수 없다. +const ITaccounting = new ITDepartment('2', ['Max']); + +Math.pow(1, 2); +const employees1 = Department.createEmployee('Max'); //정적 메소드 불러오는 방식 +console.log(employees1, Department.fiscalYear); + +ITaccounting.addEmployee('Max'); +ITaccounting.addEmployee('Manu'); + +// accounting.employees[2] = 'Anna'; +ITaccounting.describe(); +ITaccounting.printEmployeeInformation(); + +// const NewAccounting = new AccountingDepartment('d2', []); //이제 AccountingDepartment를 사용하려면 생성자가 static이기에 직접 접근방식으로 사용해야한다. + +const NewAccounting = AccountingDepartment.getInstance(); +const NewAccounting2 = AccountingDepartment.getInstance(); +//이제 이둘의 클래스 변수는 하나의 인스턴스로만 접근해서 동작하고 구현된다. +console.log(NewAccounting, NewAccounting2); + +// console.log(NewAccounting.mostRecentReport); +NewAccounting.setMostRecentReport = 'Year End Report'; +NewAccounting.addReport('Something went wrong...'); + +console.log(NewAccounting.mostRecentReport); + +NewAccounting.printReports(); \ No newline at end of file diff --git a/src/functions.ts b/src/functions.ts deleted file mode 100644 index d6fe4fb..0000000 --- a/src/functions.ts +++ /dev/null @@ -1,24 +0,0 @@ -function add(n1: number, n2: number): number { - return n1 + n2; -} - -function printResult(num: number): void { - console.log('Result: ', +num); -} - -function addAndHandle(n1: number, n2: number, cd: (num: number) => void) { - const result = n1 + n2; - return cd(result); -} - -const test = addAndHandle(10, 20, (result) => { - console.log(result); - return result; -}); - -console.log(test); -printResult(add(1, 2)); - -let result: (a: number, b: number) => number; -result = add; -console.log(result(1, 2)); diff --git a/src/union-aliases.ts.ts b/src/union-aliases.ts.ts deleted file mode 100644 index 05537bd..0000000 --- a/src/union-aliases.ts.ts +++ /dev/null @@ -1,31 +0,0 @@ -type Combinable = number | string; -type ConversionCustom = 'as-number' | 'as-text'; - -function combine( - n1: Combinable, - n2: Combinable, - resultConversion: ConversionCustom, -) { - let result; - if (typeof n1 === 'number' && typeof n2 === 'number' || resultConversion === 'as-number') { - result = +n1 + +n2; - } else if (typeof n1 === 'string' && typeof n2 === 'string') { - result = n1 + n2; - } else { - result = n1.toString() + n2.toString(); - } - // if (resultConversion === 'as-number') { - // return +result; - // } else { - // return result.toString(); - // } -} - -const combineAges = combine(20, 30, 'as-number'); -console.log(combineAges); - -const combinedStringAges = combine('20', '30', 'as-number'); -console.log(combinedStringAges); - -const combineNames = combine('Max', 'Anna', 'as-text'); -console.log(combineNames);