Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Meetup Paris TypeScript #17 - Functional Programming

Meetup Paris TypeScript #17 - Functional Programming

Do you want to take a look on Functional Progamming with TypeScript?
In this speech, we are going to introduce the paradigm basics with this language.

Sylvain PONTOREAU

January 08, 2019
Tweet

More Decks by Sylvain PONTOREAU

Other Decks in Programming

Transcript

  1. type MyFunctionType = { (value: string): boolean; }; // or

    interface MyFunctionInterface { (value: string): boolean; };
  2. let total = 0; let add = (nb: number) =>

    total += nb; add(1); // total equals 1 add(2); // total equals 3 add(3); // total equals 6
  3. let total = 0; let isNegative = () => total

    < 0; let result1 = isNegative(); // false total--; let result2 = isNegative(); // true
  4. let add = (nb1: number, nb2: number) => nb1 +

    nb2; let result1 = add(1, 2); // result1 equals 3 let result2 = add(result1, 3); // result2 equals 6 let result3 = add(result2, 4); // result3 equals 10 let result4 = add(result2, 4); // result4 equals 10
  5. const total = 0; const add = (nb: number) =>

    total += nb; type Person = { firstName: string, lastName: string }; const p: Person = { firstName: "Sylvain", lastName: "Pontoreau" }; p.firstName = "anotherFirstName";
  6. type Person = Readonly<{ firstName: string, lastName: string }>; const

    p: Person = { firstName: "Sylvain", lastName: "Pontoreau" }; p.firstName = "anotherFirstName";
  7. const personArray: ReadonlyArray<Person> = [{ firstName: "Sylvain", lastName: "Pontoreau" },

    { firstName: "Bill", lastName: "Gates" }]; personArray.push({ firstName: "Satya", lastName: "Nadella" });
  8. type Person = Readonly<{ firstName: string, lastName: string }>; const

    person: Person = { firstName: "Sylvain", lastName: "Pontoreau" }; const clone: Person = { ...person, firstName: "anotherFirstName" }; https://github.com/facebook/immutable-js
  9. const sum = (numbers: ReadonlyArray<number>) => { let result =

    0; numbers.forEach((n: number) => { result += n; }); return result; }; const result = sum([1, 2, 3, 4]); // result equals 10
  10. const sum = (numbers: ReadonlyArray<number>): number => { return numbers.length

    ? numbers[0] + sum(numbers.slice(1)) : 0; }; const result = sum([1, 2, 3, 4]); // result equals 10
  11. const handleCase1 = () => "Returns a result for case

    1"; const handleCase42 = () => "Returns a result for case 42"; const handleDefaultCase = () => "Returns a default result"; const valueToCheck = Math.random() * 42; const result = ((check) => { switch(check) { case 1: return handleCase1(); case 42: return handleCase42(); default: return handleDefaultCase(); } })(valueToCheck);
  12. type Condition<TValue> = { (value: TValue): boolean; }; type Execute<TValue,

    TResult> = { (value: TValue): TResult; }; type Pattern<TValue, TResult> = { condition: Condition<TValue>, execute: Execute<TValue, TResult> }; const when = <TValue, TResult>( condition: Condition<TValue>, execute: Execute<TValue, TResult>) => { return { condition, execute }; };
  13. const match = function<TValue, TResult>( value: TValue, defaultExecute: Execute<Tvalue, TResult>,

    ...patterns: Pattern<TValue, TResult>[]): TResult { if (patterns.length > 0) { const when = patterns[0]; return !when.condition(value) ? match( value, defaultExecute, ... patterns.slice(1)) : when.execute(value); } else { return defaultExecute(value); } }
  14. const handleCase1 = () => "Returns a result for case

    1"; const handleCase42 = () => "Returns a result for case 42"; const handleDefaultCase = () => "Returns a default result"; const valueToCheck = Math.random() * 42; const result = match( valueToCheck, handleDefaultCase, when((v) => v === 1, handleCase1), when((v) => v === 42, handleCase42) );
  15. const result = case (valueToCheck) { when 1 -> {

    return handleCase1(); } when 42 -> { return handleCase42(); } when value if (value !== 1 && value !== 42) -> { return handleDefaultCase(); } };
  16. const post = <TValue>(url: string) => { return (value: TValue)

    => { return fetch(url, { headers: { "Accept": "application/json", "Content-Type": "application/json", }, method: "POST", body: JSON.stringify(value), }); }; }; type Person = { firstName: string, lastName: string, } const postPerson = post<Person>("url"); postPerson({ firstName: "Sylvain", lastName: "Pontoreau", }).then((response) => { // Do something }); const promise = post("url")(person);
  17. interface FormatResult { (n: number): string; } interface Square {

    (n: number): number } const formatResult = (n: number) => `Result is ${ n }`; const square = (n: number) => n * n; const pipe = (format: FormatResult, square: Square) => { return (n: number) => format(square(n)) }; const result = pipe(formatResult, square)(42);
  18. declare global { interface Object { pipe<T, TResult>(this: T, next:(value:T)

    => TResult): TResult; } } Object.prototype.pipe = function<T, TResult>(this:T, next:(value:T) => TResult): TResult { return next(this); }; const nb = Math.random() * 100; const pipeResult = nb.pipe(square).pipe(formatResult);
  19. const compose = <TValue, TFirstReturn, TSecondReturn>( function1: (value: TFirstReturn) =>

    TSecondReturn, function2: (value: TValue) => TFirstReturn ) => (value: TValue) => function1(function2(value)); const kebabToSnakeCase = (s: string) => s.replace("-", "_"); const toUpper = (s: string) => s.toUpperCase(); const toScreamingSnakeCase = compose(kebabToSnakeCase, toUpper); const result = toScreamingSnakeCase("kebab-case"); // result: KEBAB_CASE
  20. class Composition<TValue, TResult> { private constructor(private readonly func : (x

    : TValue) => TResult) { } static compose<TValue, TResult>(func : (x : TValue) => TResult) { return new Composition(func); } compose<TNextValue>(f : (x : TNextValue) => TValue) : Composition<TNextValue, TResult> { return new Composition(x => this.func(f(x))) } execute(value: TValue) : TResult { return this.func(value); } } const result = Composition.compose(kebabToSnakeCase).compose(toUpper).execute("kebab-case");