diff --git a/TrungPH/ex1.ts b/TrungPH/ex1.ts new file mode 100644 index 0000000..661bd87 --- /dev/null +++ b/TrungPH/ex1.ts @@ -0,0 +1,25 @@ +interface User { + name: string; + age: number; + occupation: string; +} + +export const users: User[] = [ + { + name: 'Max Mustermann', + age: 25, + occupation: 'Chimney sweep' + }, + { + name: 'Kate Müller', + age: 23, + occupation: 'Astronaut' + } +]; + +export function logPerson(user: User) { + console.log(` - ${user.name}, ${user.age}`); +} + +console.log('Users:'); +users.forEach(logPerson); diff --git a/TrungPH/ex10.ts b/TrungPH/ex10.ts new file mode 100644 index 0000000..22ffe6e --- /dev/null +++ b/TrungPH/ex10.ts @@ -0,0 +1,117 @@ +interface User { + type: 'user'; + name: string; + age: number; + occupation: string; +} + +interface Admin { + type: 'admin'; + name: string; + age: number; + role: string; +} + +type Person = User | Admin; + +const admins: Admin[] = [ + { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' }, + { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' } +]; + +const users: User[] = [ + { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' }, + { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' } +]; + +export type ApiResponse = ( + { + status: 'success'; + data: T; + } | + { + status: 'error'; + error: string; + } +); + +type callbackFunction = (callback: (response: ApiResponse) => void) => void; +type promiseFunction = () => Promise; + +export function promisify(fn: callbackFunction): promiseFunction { + return () => new Promise((resolve, reject) => { + fn((response) => { + if (response.status === 'success') { + resolve(response.data); + } else { + reject(new Error(response.error)); + } + }); + }); +} + +const oldApi = { + requestAdmins(callback: (response: ApiResponse) => void) { + callback({ + status: 'success', + data: admins + }); + }, + requestUsers(callback: (response: ApiResponse) => void) { + callback({ + status: 'success', + data: users + }); + }, + requestCurrentServerTime(callback: (response: ApiResponse) => void) { + callback({ + status: 'success', + data: Date.now() + }); + }, + requestCoffeeMachineQueueLength(callback: (response: ApiResponse) => void) { + callback({ + status: 'error', + error: 'Numeric value has exceeded Number.MAX_SAFE_INTEGER.' + }); + } +}; + +export const api = { + requestAdmins: promisify(oldApi.requestAdmins), + requestUsers: promisify(oldApi.requestUsers), + requestCurrentServerTime: promisify(oldApi.requestCurrentServerTime), + requestCoffeeMachineQueueLength: promisify(oldApi.requestCoffeeMachineQueueLength) +}; + +function logPerson(person: Person) { + console.log( + ` - ${person.name}, ${person.age}, ${person.type === 'admin' ? person.role : person.occupation}` + ); +} + +async function startTheApp() { + console.log('Admins:'); + (await api.requestAdmins()).forEach(logPerson); + console.log(); + + console.log('Users:'); + (await api.requestUsers()).forEach(logPerson); + console.log(); + + console.log('Server time:'); + console.log(` ${new Date(await api.requestCurrentServerTime()).toLocaleString()}`); + console.log(); + + console.log('Coffee machine queue length:'); + console.log(` ${await api.requestCoffeeMachineQueueLength()}`); +} + +startTheApp().then( + () => { + console.log('Success!'); + }, + (e: Error) => { + console.log(`Error: "${e.message}", but it's fine, sometimes errors are inevitable.`); + } +); diff --git a/TrungPH/ex11.d.ts b/TrungPH/ex11.d.ts new file mode 100644 index 0000000..e6ff463 --- /dev/null +++ b/TrungPH/ex11.d.ts @@ -0,0 +1,41 @@ + +declare module 'str-utils' { + // export const ... + // export function ... + + /** +* Reverses a string. +* @param {String} value +* @return {String} +*/ +export function strReverse(value: string): string; + +/** +* Converts a string to lower case. +* @param {String} value +* @return {String} +*/ +export function strToLower(value: string): string; + +/** +* Converts a string to upper case. +* @param {String} value +* @return {String} +*/ +export function strToUpper(value: string): string; + +/** +* Randomizes characters of a string. +* @param {String} value +* @return {String} +*/ +export function strRandomize(value: string): string; + +/** +* Inverts case of a string. +* @param {String} value +* @return {String} +*/ +export function strInvertCase(value: string): string; + +} diff --git a/TrungPH/ex12.d.ts b/TrungPH/ex12.d.ts new file mode 100644 index 0000000..b8319ef --- /dev/null +++ b/TrungPH/ex12.d.ts @@ -0,0 +1,17 @@ +declare module 'stats' { + type Comparator = (a: T, b: T) => number; + type GetIndex = (input: T[], comparator: Comparator) => number; + + export const getMinIndex: GetIndex; + export const getMedianIndex: GetIndex; + export const getMaxIndex: GetIndex; + + + type GetElement = (input: T[], comparator: Comparator) => null | T; + + export const getMinElement: GetElement; + export const getMedianElement: GetElement; + export const getMaxElement: GetElement; + + export const getAverageValue: (input: T[], getValue: (item: T) => number) => number | null; +} diff --git a/TrungPH/ex13.d.ts b/TrungPH/ex13.d.ts new file mode 100644 index 0000000..aaf86bc --- /dev/null +++ b/TrungPH/ex13.d.ts @@ -0,0 +1,12 @@ +// This enables module augmentation mode. +import 'date-wizard'; + +declare module 'date-wizard' { + interface DateDetails { + hours: number; + minutes: number, + seconds: number + } + + function pad(input: number): string +} diff --git a/TrungPH/ex2.ts b/TrungPH/ex2.ts new file mode 100644 index 0000000..39b3a15 --- /dev/null +++ b/TrungPH/ex2.ts @@ -0,0 +1,42 @@ +interface User { + name: string; + age: number; + occupation: string; +} + +interface Admin { + name: string; + age: number; + role: string; +} + +export type Person = User | Admin; + +export const persons: Person[] = [ + { + name: 'Max Mustermann', + age: 25, + occupation: 'Chimney sweep' + }, + { + name: 'Jane Doe', + age: 32, + role: 'Administrator' + }, + { + name: 'Kate Müller', + age: 23, + occupation: 'Astronaut' + }, + { + name: 'Bruce Willis', + age: 64, + role: 'World saver' + } +]; + +export function logPerson(person: Person) { + console.log(` - ${person.name}, ${person.age}`); +} + +persons.forEach(logPerson); diff --git a/TrungPH/ex3.ts b/TrungPH/ex3.ts new file mode 100644 index 0000000..1279874 --- /dev/null +++ b/TrungPH/ex3.ts @@ -0,0 +1,54 @@ +interface User { + type: 'user'; + name: string; + age: number; + occupation: string; +} + +interface Admin { + type: 'admin'; + name: string; + age: number; + role: string; +} + +export type Person = User | Admin; + +export const persons: Person[] = [ + { + type: 'user', + name: 'Max Mustermann', + age: 25, + occupation: 'Chimney sweep' + }, + { + type: 'admin', + name: 'Jane Doe', + age: 32, + role: 'Administrator' + }, + { + type: 'user', + name: 'Kate Müller', + age: 23, + occupation: 'Astronaut' + }, + { + type: 'admin', + name: 'Bruce Willis', + age: 64, + role: 'World saver' + } +]; + +export function logPerson(person: Person) { + let additionalInformation: string; + if (person.type === 'admin') { + additionalInformation = person.role; + } else { + additionalInformation = person.occupation; + } + console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`); +} + +persons.forEach(logPerson); diff --git a/TrungPH/ex4.ts b/TrungPH/ex4.ts new file mode 100644 index 0000000..a53e841 --- /dev/null +++ b/TrungPH/ex4.ts @@ -0,0 +1,49 @@ +interface User { + type: 'user'; + name: string; + age: number; + occupation: string; +} + +interface Admin { + type: 'admin'; + name: string; + age: number; + role: string; +} + +export type Person = User | Admin; + +export const persons: Person[] = [ + { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' }, + { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' }, + { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' }, + { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' } +]; + +export function isAdmin(person: Person): person is Admin { + return person.type === 'admin'; +} + +export function isUser(person: Person): person is User { + return person.type === 'user'; +} + +export function logPerson(person: Person) { + let additionalInformation: string = ''; + if (isAdmin(person)) { + additionalInformation = person.role; + } + if (isUser(person)) { + additionalInformation = person.occupation; + } + console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`); +} + +console.log('Admins:'); +persons.filter(isAdmin).forEach(logPerson); + +console.log(); + +console.log('Users:'); +persons.filter(isUser).forEach(logPerson); \ No newline at end of file diff --git a/TrungPH/ex5.ts b/TrungPH/ex5.ts new file mode 100644 index 0000000..a323ede --- /dev/null +++ b/TrungPH/ex5.ts @@ -0,0 +1,58 @@ +interface User { + type: 'user'; + name: string; + age: number; + occupation: string; +} + +interface Admin { + type: 'admin'; + name: string; + age: number; + role: string; +} + +export type Person = User | Admin; + +export const persons: Person[] = [ + { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' }, + { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' }, + { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' }, + { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' }, + { type: 'user', name: 'Wilson', age: 23, occupation: 'Ball' }, + { type: 'admin', name: 'Agent Smith', age: 23, role: 'Administrator' } +]; + +export const isAdmin = (person: Person): person is Admin => person.type === 'admin'; +export const isUser = (person: Person): person is User => person.type === 'user'; + +export function logPerson(person: Person) { + let additionalInformation = ''; + if (isAdmin(person)) { + additionalInformation = person.role; + } + if (isUser(person)) { + additionalInformation = person.occupation; + } + console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`); +} + +export function filterUsers(persons: Person[], criteria?: Partial): User[] { + if (!criteria) return persons.filter(isUser); // return all users if no criteria is specified + + return persons.filter(isUser).filter((user) => { + const criteriaKeys = Object.keys(criteria) as (keyof User)[]; + return criteriaKeys.every((fieldName) => { + return user[fieldName] === criteria[fieldName]; + }); + }); +} + +console.log('Users of age 23:'); + +filterUsers( + persons, + { + age: 23 + } +).forEach(logPerson); diff --git a/TrungPH/ex6.ts b/TrungPH/ex6.ts new file mode 100644 index 0000000..a5b9430 --- /dev/null +++ b/TrungPH/ex6.ts @@ -0,0 +1,54 @@ +interface User { + type: 'user'; + name: string; + age: number; + occupation: string; +} + +interface Admin { + type: 'admin'; + name: string; + age: number; + role: string; +} + +export type Person = User | Admin; + +export const persons: Person[] = [ + { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' }, + { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' }, + { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' }, + { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' }, + { type: 'user', name: 'Wilson', age: 23, occupation: 'Ball' }, + { type: 'admin', name: 'Agent Smith', age: 23, role: 'Anti-virus engineer' } +]; + +export function logPerson(person: Person) { + console.log( + ` - ${person.name}, ${person.age}, ${person.type === 'admin' ? person.role : person.occupation}` + ); +} + +export function filterPersons(persons: Person[], personType: User['type'], criteria: Partial>): User[]; +export function filterPersons(persons: Person[], personType: Admin['type'], criteria: Partial>): Admin[]; +export function filterPersons(persons: Person[], personType: string, criteria: Partial): Person[] { + return persons + .filter((person) => person.type === personType) + .filter((person) => { + let criteriaKeys = Object.keys(criteria) as (keyof Person)[]; + return criteriaKeys.every((fieldName) => { + return person[fieldName] === criteria[fieldName]; + }); + }); +} + +export const usersOfAge23 = filterPersons(persons, 'user', { age: 23 }); +export const adminsOfAge23 = filterPersons(persons, 'admin', { age: 23 }); + +console.log('Users of age 23:'); +usersOfAge23.forEach(logPerson); + +console.log(); + +console.log('Admins of age 23:'); +adminsOfAge23.forEach(logPerson); diff --git a/TrungPH/ex7.ts b/TrungPH/ex7.ts new file mode 100644 index 0000000..9fb334b --- /dev/null +++ b/TrungPH/ex7.ts @@ -0,0 +1,96 @@ +interface User { + type: 'user'; + name: string; + age: number; + occupation: string; +} + +interface Admin { + type: 'admin'; + name: string; + age: number; + role: string; +} + +export type Person = User | Admin; + +function logUser(user: User) { + const pos = users.indexOf(user) + 1; + console.log(` - #${pos} User: ${user.name}, ${user.age}, ${user.occupation}`); +} + +function logAdmin(admin: Admin) { + const pos = admins.indexOf(admin) + 1; + console.log(` - #${pos} Admin: ${admin.name}, ${admin.age}, ${admin.role}`); +} + +const admins: Admin[] = [ + { + type: 'admin', + name: 'Will Bruces', + age: 30, + role: 'Overseer' + }, + { + type: 'admin', + name: 'Steve', + age: 40, + role: 'Steve' + } +]; + +const users: User[] = [ + { + type: 'user', + name: 'Moses', + age: 70, + occupation: 'Desert guide' + }, + { + type: 'user', + name: 'Superman', + age: 28, + occupation: 'Ordinary person' + } +]; + +export function swap(v1: Input1, v2: Input2): [Input2, Input1] { + return [v2, v1]; +} + +function test1() { + console.log('test1:'); + const [secondUser, firstAdmin] = swap(admins[0], users[1]); + logUser(secondUser); + logAdmin(firstAdmin); +} + +function test2() { + console.log('test2:'); + const [secondAdmin, firstUser] = swap(users[0], admins[1]); + logAdmin(secondAdmin); + logUser(firstUser); +} + +function test3() { + console.log('test3:'); + const [secondUser, firstUser] = swap(users[0], users[1]); + logUser(secondUser); + logUser(firstUser); +} + +function test4() { + console.log('test4:'); + const [firstAdmin, secondAdmin] = swap(admins[1], admins[0]); + logAdmin(firstAdmin); + logAdmin(secondAdmin); +} + +function test5() { + console.log('test5:'); + const [stringValue, numericValue] = swap(123, 'Hello World'); + console.log(` - String: ${stringValue}`); + console.log(` - Numeric: ${numericValue}`); +} + +[test1, test2, test3, test4, test5].forEach((test) => test()); diff --git a/TrungPH/ex8.ts b/TrungPH/ex8.ts new file mode 100644 index 0000000..cc2b07d --- /dev/null +++ b/TrungPH/ex8.ts @@ -0,0 +1,72 @@ +interface User { + type: 'user'; + name: string; + age: number; + occupation: string; +} + +interface Admin { + type: 'admin'; + name: string; + age: number; + role: string; +} + +type PowerUser = Omit & Omit & { + type: 'powerUser'; +}; + +export type Person = User | Admin | PowerUser; + +export const persons: Person[] = [ + { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' }, + { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' }, + { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' }, + { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' }, + { + type: 'powerUser', + name: 'Nikki Stone', + age: 45, + role: 'Moderator', + occupation: 'Cat groomer' + } +]; + +function isAdmin(person: Person): person is Admin { + return person.type === 'admin'; +} + +function isUser(person: Person): person is User { + return person.type === 'user'; +} + +function isPowerUser(person: Person): person is PowerUser { + return person.type === 'powerUser'; +} + +export function logPerson(person: Person) { + let additionalInformation: string = ''; + if (isAdmin(person)) { + additionalInformation = person.role; + } + if (isUser(person)) { + additionalInformation = person.occupation; + } + if (isPowerUser(person)) { + additionalInformation = `${person.role}, ${person.occupation}`; + } + console.log(`${person.name}, ${person.age}, ${additionalInformation}`); +} + +console.log('Admins:'); +persons.filter(isAdmin).forEach(logPerson); + +console.log(); + +console.log('Users:'); +persons.filter(isUser).forEach(logPerson); + +console.log(); + +console.log('Power users:'); +persons.filter(isPowerUser).forEach(logPerson); diff --git a/TrungPH/ex9.ts b/TrungPH/ex9.ts new file mode 100644 index 0000000..0dc781f --- /dev/null +++ b/TrungPH/ex9.ts @@ -0,0 +1,129 @@ +interface User { + type: 'user'; + name: string; + age: number; + occupation: string; +} + +interface Admin { + type: 'admin'; + name: string; + age: number; + role: string; +} + +type Person = User | Admin; + +const admins: Admin[] = [ + { type: 'admin', name: 'Jane Doe', age: 32, role: 'Administrator' }, + { type: 'admin', name: 'Bruce Willis', age: 64, role: 'World saver' } +]; + +const users: User[] = [ + { type: 'user', name: 'Max Mustermann', age: 25, occupation: 'Chimney sweep' }, + { type: 'user', name: 'Kate Müller', age: 23, occupation: 'Astronaut' } +]; + +export type ApiResponse = ( + { + status: 'success'; + data: T; + } | + { + status: 'error'; + error: string; + } +); + +type AdminsApiResponse = ApiResponse; + +type UsersApiResponse = ApiResponse; + +export function requestAdmins(callback: (response: AdminsApiResponse) => void) { + callback({ + status: 'success', + data: admins + }); +} + +export function requestUsers(callback: (response: UsersApiResponse) => void) { + callback({ + status: 'success', + data: users + }); +} + +export function requestCurrentServerTime(callback: (response: ApiResponse) => void) { + callback({ + status: 'success', + data: Date.now() + }); +} + +export function requestCoffeeMachineQueueLength(callback: (response: ApiResponse) => void) { + callback({ + status: 'error', + error: 'Numeric value has exceeded Number.MAX_SAFE_INTEGER.' + }); +} + +function logPerson(person: Person) { + console.log( + ` - ${person.name}, ${person.age}, ${person.type === 'admin' ? person.role : person.occupation}` + ); +} + +function startTheApp(callback: (error: Error | null) => void) { + requestAdmins((adminsResponse) => { + console.log('Admins:'); + if (adminsResponse.status === 'success') { + adminsResponse.data.forEach(logPerson); + } else { + return callback(new Error(adminsResponse.error)); + } + + console.log(); + + requestUsers((usersResponse) => { + console.log('Users:'); + if (usersResponse.status === 'success') { + usersResponse.data.forEach(logPerson); + } else { + return callback(new Error(usersResponse.error)); + } + + console.log(); + + requestCurrentServerTime((serverTimeResponse) => { + console.log('Server time:'); + if (serverTimeResponse.status === 'success') { + console.log(` ${new Date(serverTimeResponse.data).toLocaleString()}`); + } else { + return callback(new Error(serverTimeResponse.error)); + } + + console.log(); + + requestCoffeeMachineQueueLength((coffeeMachineQueueLengthResponse) => { + console.log('Coffee machine queue length:'); + if (coffeeMachineQueueLengthResponse.status === 'success') { + console.log(` ${coffeeMachineQueueLengthResponse.data}`); + } else { + return callback(new Error(coffeeMachineQueueLengthResponse.error)); + } + + callback(null); + }); + }); + }); + }); +} + +startTheApp((e: Error | null) => { + console.log(); + if (e) { + console.log(`Error: "${e.message}", but it's fine, sometimes errors are inevitable.`) + } else { + console.log('Success!'); + } +});