diff --git a/src/12-testing/KATA - Solution/tests/UserService.test.ts b/src/12-testing/KATA - Solution/tests/UserService.test.ts index 4eab43d..ec76858 100644 --- a/src/12-testing/KATA - Solution/tests/UserService.test.ts +++ b/src/12-testing/KATA - Solution/tests/UserService.test.ts @@ -20,10 +20,10 @@ describe('UserService', () => { expect(user).toEqual({ id: 1000, username: 'Test User' }); expect(apiService.fetchUser).toHaveBeenCalledWith(1000); + expect(apiService.fetchUser).toHaveBeenCalledTimes(1); }); test('getUserById should throw an error if ID is missing', () => { - const userService = new UserService(null as unknown as ApiService); expect(() => userService.getUserById(undefined as unknown as number) ).toThrow('ID is required'); @@ -32,10 +32,15 @@ describe('UserService', () => { test('getAllUsers should return a list of users', async () => { apiService.fetchAllUsers.mockResolvedValue([ { id: 2000, username: 'User 1' }, + { id: 2001, username: 'User 2' }, ]); const users = await userService.getAllUsers(); - expect(users).toEqual([{ id: 2000, username: 'User 1' }]); + expect(users).toEqual([ + { id: 2000, username: 'User 1' }, + { id: 2001, username: 'User 2' }, + ]); + expect(users.length).toBe(2); expect(apiService.fetchAllUsers).toHaveBeenCalled(); }); }); diff --git a/src/13-funktionale-programmierung/.vscode/settings.json b/src/13-funktionale-programmierung/.vscode/settings.json new file mode 100644 index 0000000..c6c736a --- /dev/null +++ b/src/13-funktionale-programmierung/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "github.copilot.enable": { + "*": false, + "plaintext": false, + "markdown": false, + "scminput": false + }, + "deno.enable": true +} diff --git a/src/13-funktionale-programmierung/composition.ts b/src/13-funktionale-programmierung/composition.ts new file mode 100644 index 0000000..b6f6e54 --- /dev/null +++ b/src/13-funktionale-programmierung/composition.ts @@ -0,0 +1,86 @@ +function toUpperCase(str: string): string { + return str.toUpperCase(); +} + +function addExclamation(str: string): string { + return str + '!'; +} + +function addPrefix(str: string): string { + return 'abc ' + str; +} + +function greet(name: string): string { + return addExclamation(toUpperCase('Hello ' + name)); +} + +console.log(greet('Lars')); + +function compose(...functions: ((arg: T) => T)[]): (arg: T) => T { + return (arg: T) => functions.reduceRight((result, fn) => fn(result), arg); +} + +const enhanceText = compose(addPrefix, toUpperCase, addPrefix, addExclamation); + +console.log(enhanceText('hello')); + +type GenericFn = (a: any) => any; + +function composeGeneric(...fns: GenericFn[]) { + return function composed(inital: any) { + return fns.reduceRight((value, fn) => fn(value), inital); + }; +} + +const addHello = (str: string) => `Hello ${str}`; +const makeBold = (str: string) => `${str}`; +const toObj = (str: string) => ({ + html: str, +}); + +const composedFn = composeGeneric(toObj, makeBold, addHello); +console.log(composedFn('World')); + +function pipe(...functions: ((arg: T) => T)[]): (arg: T) => T { + return (arg: T) => functions.reduce((result, fn) => fn(result), arg); +} + +const enhanceTextPipe = pipe( + (str: string) => 'Hello ' + str, + addPrefix, + toUpperCase, + makeBold, + addExclamation +); +console.log(enhanceTextPipe('Max')); + +class StringProcessor { + constructor(private value: string) {} + + toUpperCase(): this { + this.value = this.value.toUpperCase(); + return this; + } + + addExclamation(): this { + this.value = this.value + '!'; + return this; + } + + prependHello(): this { + this.value = 'Hello ' + this.value; + return this; + } + + getResult(): string { + return this.value; + } +} + +const result = new StringProcessor('alice') + .toUpperCase() + .prependHello() + .addExclamation() + .getResult(); + +console.log(result); diff --git a/src/13-funktionale-programmierung/currying.ts b/src/13-funktionale-programmierung/currying.ts new file mode 100644 index 0000000..897bd01 --- /dev/null +++ b/src/13-funktionale-programmierung/currying.ts @@ -0,0 +1,25 @@ +function add(a: number, b: number): number { + return a + b; +} + +function multiply(a: number, b: number) { + return a * b; +} + +console.log(add(2, 3)); + +function curriedAdd(a: number): (b: number) => number { + return (b: number) => a + b; +} + +const addTwo = curriedAdd(2); +console.log(addTwo(3)); + +function curry(fn: (a: T, b: U) => R): (a: T) => (b: U) => R { + return (a: T) => (b: U) => fn(a, b); +} + +const curriedMultiply = curry(multiply); + +const multiplyByThree = curriedMultiply(3); +console.log(multiplyByThree(4)); diff --git a/src/13-funktionale-programmierung/higher-order-functions.ts b/src/13-funktionale-programmierung/higher-order-functions.ts new file mode 100644 index 0000000..5c5662b --- /dev/null +++ b/src/13-funktionale-programmierung/higher-order-functions.ts @@ -0,0 +1,33 @@ +function applyFunction(fn: (x: number) => number, value: number): number { + return fn(value); +} + +function double(x: number): number { + return x * 2; +} + +console.log(applyFunction(double, 5)); + +const numbers = [1, 2, 3, 4]; +const doubleNumbers = numbers.map((n) => n * 2); +console.log(doubleNumbers); + +function createMultipler(factor: number): (x: number) => number { + return (x: number) => x * factor; +} + +const triple = createMultipler(3); + +console.log(triple(5)); + +function compose(...functions: ((arg: T) => T)[]): (arg: T) => T { + return (arg: T) => functions.reduceRight((result, fn) => fn(result), arg); +} + +const processNumber = compose( + (x: number) => x + 1, + (x: number) => x * 2, + (x: number) => x - 3 +); + +console.log(processNumber(50)); diff --git a/src/13-funktionale-programmierung/index.ts b/src/13-funktionale-programmierung/index.ts new file mode 100644 index 0000000..bfca2bb --- /dev/null +++ b/src/13-funktionale-programmierung/index.ts @@ -0,0 +1,41 @@ +const numbers: number[] = [1, 2, 3, 4, 5]; + +const doubleFn = (num: number): number => num * 2; + +const doubledNumbers: number[] = numbers.map(doubleFn); + +console.log(doubledNumbers); +console.log(doubleFn(52)); + +const filterEven = (num: number): boolean => num % 2 === 0; +console.log(numbers.filter(filterEven)); + +const sumFn = (total: number, current: number) => total + current; +console.log(numbers.reduce(sumFn, 0)); + +function doubleArray(arr: T[]): T[] { + return arr.map(doubleFn) as T[]; +} + +type Celsius = number; +type Fahrenheit = number; + +function scaleTemperatures( + temps: T[], + factor: number, + offset: number = 0 +): T[] { + return temps.map((temp) => (temp * factor + offset) as T); +} + +const temperaturesC: Celsius[] = [10, 20, 30]; +const temperaturesF: Fahrenheit[] = scaleTemperatures(temperaturesC, 1.8, 32); + +console.log(temperaturesF); + +const result: number = numbers + .filter(filterEven) + .map(doubleFn) + .reduce(sumFn, 0); + +console.log(result); diff --git a/src/13-funktionale-programmierung/pure-functions.ts b/src/13-funktionale-programmierung/pure-functions.ts new file mode 100644 index 0000000..043ed64 --- /dev/null +++ b/src/13-funktionale-programmierung/pure-functions.ts @@ -0,0 +1,48 @@ +function add(a: number, b: number): number { + return a + b; +} + +console.log(add(2, 3)); +console.log(add(2, 3)); +console.log(add(2, 3)); +console.log(add(2, 3)); + +let total = 0; + +function addToTotal(value: number): number { + total += value; + return total; +} + +console.log(addToTotal(5)); +console.log(addToTotal(5)); +console.log(addToTotal(5)); +console.log(addToTotal(5)); + +function addItem(array: T[], item: T): T[] { + return [...array, item]; +} + +const numbers = [1, 2, 3]; +console.log(numbers); +const newNumbers = numbers; + +numbers.push(4); + +// const newNumbers = addItem(numbers, 99); + +console.log(numbers); +console.log(newNumbers); + +const person = { name: 'Alice', age: 25 }; +person.age = 26; +console.log(person); + +const updatedPerson = { ...person, age: 26 }; +console.log(updatedPerson); + +type User = Readonly<{ name: string; age: number }>; +const user: User = { name: 'charly', age: 21 }; +// user.age = 22; +const updateUser = { ...user, age: 22 }; +console.log(updateUser);