diff --git a/chapter02/package.json b/chapter02/package.json index 859480d..894b0a7 100644 --- a/chapter02/package.json +++ b/chapter02/package.json @@ -15,10 +15,7 @@ "author": "Federico Kereki", "license": "ISC", "babel": { - "presets": [ - "env", - "flow" - ] + "presets": ["env", "flow"] }, "eslintConfig": { "parserOptions": { @@ -31,16 +28,12 @@ "node": true, "es6": true }, - "extends": [ - "eslint:recommended", - "plugin:flowtype/recommended" - ], - "plugins": [ - "babel", - "flowtype" - ], + "extends": ["eslint:recommended", "plugin:flowtype/recommended"], + "plugins": ["babel", "flowtype"], "rules": { - "no-console": "off" + "no-console": "off", + "no-var": "error", + "prefer-const": "error" } }, "prettier": { diff --git a/chapter02/src/arrow_functions.js b/chapter02/src/arrow_functions.js new file mode 100644 index 0000000..67abf76 --- /dev/null +++ b/chapter02/src/arrow_functions.js @@ -0,0 +1,40 @@ +/* @flow */ +/* eslint-disable no-unused-vars, one-var */ + +function Show(value: mixed): void { + this.saved = value; + setTimeout(function() { + console.log(this.saved); + }, 1000); +} + +const w = new Show("Doesn't work..."); // instead, "undefined" is shown + +function Show1(value: mixed): void { + this.saved = value; + setTimeout( + function() { + console.log(this.saved); + }.bind(this), + 1000 + ); +} + +function Show2(value: mixed): void { + this.saved = value; + const that = this; + setTimeout(function() { + console.log(that.saved); + }, 2000); +} + +function Show3(value: mixed): void { + this.saved = value; + setTimeout(() => { + console.log(this.saved); + }, 3000); +} + +const x = new Show1("This"); +const y = new Show2("always"); +const z = new Show3("works"); diff --git a/chapter02/src/opaque_types.js b/chapter02/src/opaque_types.js new file mode 100644 index 0000000..b16e1fb --- /dev/null +++ b/chapter02/src/opaque_types.js @@ -0,0 +1,40 @@ +/* @flow */ +/* eslint-disable no-unused-vars */ + +opaque type dniType: string = string; +type nameType = string; // not opaque! + +const stringToDni = (st: string): dniType => { + /* + do validations on st + if OK, return a dniType + if wrong, throw an error + */ + return (st: dniType); +}; + +export type { dniType, nameType }; +export { stringToDni }; + +class Client { + id: number; + dni: dniType; + name: nameType; + securityToken: string; + + constructor(anId: number, aDni: dniType, aName: nameType) { + this.id = anId; + this.dni = aDni; + this.name = aName; + + this.securityToken = "generate.some.token.somehow"; + } + + showNameAndDni(t: string): void { + console.log(`${t} - Name: ${this.name} DNI: ${this.dni}`); + } + + useTokenForSomething(): void { + // do something with the token + } +} diff --git a/chapter02/src/opaque_usage.js b/chapter02/src/opaque_usage.js new file mode 100644 index 0000000..cfac997 --- /dev/null +++ b/chapter02/src/opaque_usage.js @@ -0,0 +1,28 @@ +/* @flow */ +/* eslint-disable no-unused-vars */ + +import type { dniType, nameType } from "./opaque_types"; +import { stringToDni } from "./opaque_types"; + +function updateClient(id: number, dni: dniType, name: nameType) { + /* + Talk to some server + Update the dni and name for the client with given id + */ +} + +const newDni = "1234567-8"; // supposedly a DNI +const newName = "Kari Nordmann"; + +updateClient(229, newName, newDni); // doesn't work; 2nd argument should be a dni +updateClient(229, newDni, newName); // doesn't work either; same reason +updateClient(229, stringToDni(newDni), newName); // OK! + +/* + Constraints +*/ +function showText(st: string) { + console.log(`Important message: ${st}`); +} +const anotherDni: dniType = stringToDni("9876543-2"); +showText(anotherDni); // error, if no subtype constraint is added! diff --git a/chapter02/src/spread_and_rest.js b/chapter02/src/spread_and_rest.js index 9046119..3ecf86e 100644 --- a/chapter02/src/spread_and_rest.js +++ b/chapter02/src/spread_and_rest.js @@ -1,5 +1,5 @@ /* @flow */ -/* eslint-disable no-unused-vars */ +/* eslint-disable prefer-const,no-unused-vars,no-unused-labels */ let values = [22, 9, 60, 12, 4, 56]; const maxOfValues = Math.max(...values); // 60 @@ -14,11 +14,17 @@ let person = { name: "Juan", age: 24 }; let copyOfPerson = { ...person }; let expandedPerson = { ...person, sister: "MarĂ­a" }; -const average = (...nums: Array): number => { +function average(...nums: Array): number { let sum = 0; for (let i = 0; i < nums.length; i++) { sum += nums[i]; } return sum / nums.length; -}; +} console.log(average(22, 9, 60, 12, 4, 56)); // 27.166667 + +const simpleAction = (t: string, d: mixed): Object => { + type: t; + data: d; + return {}; +}; diff --git a/chapter02/src/types_basic.js b/chapter02/src/types_basic.js index 8cc533c..7f023e3 100644 --- a/chapter02/src/types_basic.js +++ b/chapter02/src/types_basic.js @@ -24,10 +24,17 @@ numbersList[1] = "SEP"; // error; cannot assign a string to a number let anotherList: number[]; -let sealedObject: { name: string, age?: number }; +let sealedObject: { name: string, age?: number } = { name: "" }; sealedObject.name = "Ivan Horvat"; // OK sealedObject.id = 229; // error: key isn't defined in the data type -sealedObject = { age: 57 }; // error: mandatory field is missing +sealedObject = { age: 57 }; // error: mandatory "name" field is missing let unsealedObject = {}; unsealedObject.id = 229; // OK + +const toString2 = (x: number): string => { + return x + "x"; +}; + +type numberToString = number => string; +const toString3: numberToString = (x: number) => String(x);