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.

9298dcce5b2b0e88d8ffbb837192ca98?s=128

Sylvain Pontoreau

January 08, 2019
Tweet

Transcript

  1. Paris TypeScript January 8th 2018

  2. Premier Field Engineer @spontoreau In ❤️ with Co-organizer

  3. None
  4. None
  5. None
  6. type MyFunctionType = { (value: string): boolean; }; // or

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

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

    < 0; let result1 = isNegative(); // false total--; let result2 = isNegative(); // true
  10. 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
  11. None
  12. 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";
  13. type Person = Readonly<{ firstName: string, lastName: string }>; const

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

    { firstName: "Bill", lastName: "Gates" }]; personArray.push({ firstName: "Satya", lastName: "Nadella" });
  15. 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
  16. 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
  17. 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
  18. 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);
  19. 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 }; };
  20. 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); } }
  21. 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) );
  22. const result = case (valueToCheck) { when 1 -> {

    return handleCase1(); } when 42 -> { return handleCase42(); } when value if (value !== 1 && value !== 42) -> { return handleDefaultCase(); } };
  23. 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);
  24. 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);
  25. 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);
  26. const nb = Math.random() * 100; const result = nb

    |> square |> formatResult;
  27. 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
  28. 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");
  29. None
  30. None
  31. None