Introduction to Javascript type systems

Written on December 21, 2017

https://www.slideshare.net/SooKim17/sookim-171221

기본 문법 비교

// @flow

// bool
const isDone: boolean = false

// number
const decimal: number = 6

// string
const color: string = "blue"

// array
const list: Array<number> = [1, 2, 3]

// tuple
const x: [string, number] = ["hello", 10]

// object, no dynamic binding
let obj2: { bar: number } = { bar: 1 }
obj2.foo = 2 // Property not found in object literal

// structural typing
interface Named {
  name: string
}
class Person {
  name: string
}
let p: Named
p = new Person() // OK, because of structural typing

// subtype
let a: Named
const y = { name: "Alice", location: "Seattle" } // y's inferred type is { name: string; location: string; }
a = y

// generic
interface NotEmpty<T> {
  data: T
}
let b: NotEmpty<number>

// intersection
type A = { a: number }
type B = { b: boolean }
type C = { c: string }

function method(value: A & B & C) {
  // ...
}

// literal & union
type Color = "Red" | "Green"
type Result = "success" | "danger"
// function getColor(name: Result): Color {
function getColor(name: Result) {
  switch (name) {
    case "success": return "Green"
    case "danger": return "Red"
  }
  // throw new Error("ss")
  name
}
getColor("success") // Works!
getColor("danger")  // Works!
getColor("error")   // Error!

// union refinement
type Success = {kind: "success", value: 1}
type Danger = {kind: "danger", message: "e"}
type Result2 = Success | Danger
function getColor2(name: Result2): Color {
  if (name.kind === "success") {
    return "Green"
  } else if (name.kind === "danger"){
    return "Red"
  }
  else {
    // if ask type of name, not covered -> likely be unreachable
    // but if else do not exist, return type is Color | void. refinement is not working.
    // can make a guess using "not covered" as refinement
    // to ways to solve this
    // 1. return unreacable in else
    // 2. throw error in else
    name
    throw new 
    return "Red"
    // throw new Error("unreachable")
  }
}

type Nat =
  null
  | () => Nat

const zero : Nat = null
const succ : Nat => Nat = n => () => n
const succ1 : Nat => null = n => () => n
const one : Nat = () => zero
const two : Nat = () => one
const two1 : Nat = () => 1

const nat2Int : Nat => number = n => {
  if (n === null) {
    n()
    return 0
  } else {
    n
    return 1 + nat2Int(n())
  }
}

console.log(nat2Int(two))
console.log(nat2Int(succ(succ(zero))))
// typescript

// bool
const isDone: boolean = false

// number
const decimal: number = 6

// string
const color: string = "blue"

// array
const list: Array<number> = [1, 2, 3]

// tuple
const x: [string, number] = ["hello", 10]

// object, no dynamic binding
let obj2: { bar: number } = { bar: 1 };
obj2.foo = 2; // Property not found in object literal

// structural typing
interface Named {
  name: string;
}
class Person {
  name: string;
}
let p: Named;
p = new Person(); // OK, because of structural typing

// subtype
let a: Named;
let y = { name: "Alice", location: "Seattle" }; // y's inferred type is { name: string; location: string; }
a = y;

// generic
interface NotEmpty<T> {
  data: T;
}
let b: NotEmpty<number>;

// intersection
type A = { a: number };
type B = { b: boolean };
type C = { c: string };

function method(value: A & B & C) {
  // ...
}

// literal & union
type Color = "Red" | "Green"
type Result = "success" | "danger"
// function getColor(name: Result): Color {
function getColor(name: Result) {
  switch (name) {
    case "success": return "Green";
    case "danger": return "Red";
  }
  // throw new Error("ss")
  name
}
getColor("success"); // Works!
getColor("danger");  // Works!
getColor("error");   // Error!

// union refinement
type Success = { kind: "success", value: 1 }
type Danger = { kind: "danger", message: "e" }
type Result2 = Success | Danger
function getColor2(name: Result2): Color {
  name
  if (name.kind === "success") {
    name
    return "Green"
  } else if (name.kind === "danger") {
    name
    return "Red"
  } else {
    // if ask type of name, not covered -> likely be unreachable
    // but if else do not exist, return type is Color | void. refinement is not working.
    // can make a guess using "not covered" as refinement
    name
    return "Red"
  }
}

type Nat =
  null
  | (() => Nat)

const zero: Nat = null
const succ: (n: Nat) => Nat = n => () => n
const succ1: (n: Nat) => null = n => (() => n)
const one: Nat = () => zero
const two: Nat = () => one
const two1: Nat = () => 1

const nat2Int: (n: Nat) => number = n => {
  if (n === null) {
    n()
    return 0
  } else {
    n
    return 1 + nat2Int(n())
  }
}

console.log(nat2Int(two))
console.log(nat2Int(succ(succ(zero))))
diff --git a/points.ts b/points.ts
index fe11aad..895c042 100644
--- a/points.ts
+++ b/points.ts
@@ -1,4 +1,4 @@
-// typescript
+// @flow
 
 // bool
 const isDone: boolean = false;
@@ -31,7 +31,7 @@ p = new Person(); // OK, because of structural typing
 
 // subtype
 let a: Named;
-let y = { name: "Alice", location: "Seattle" }; // y's inferred type is { name: string; location: string; }
+const y = { name: "Alice", location: "Seattle" }; // y's inferred type is { name: string; location: string; }
 a = y;
 
 // generic
@@ -78,23 +78,27 @@ function getColor2(name: Result2): Color {
     // if ask type of name, not covered -> likely be unreachable
     // but if else do not exist, return type is Color | void. refinement is not working.
     // can make a guess using "not covered" as refinement
-    name;
-    return "Red";
+    // to ways to solve this
+    // 1. return unreacable in else
+    // 2. throw error in else
+    name
+    return "Red"
+    // throw new Error("unreachable")
   }
 }
 
 type Nat =
   null
-  | (() => Nat)
+  | () => Nat
 
 const zero: Nat = null
-const succ: (n: Nat) => Nat = n => () => n
-const succ1: (n: Nat) => null = n => (() => n)
+const succ: Nat => Nat = n => () => n
+const succ1: Nat => null = n => () => n
 const one: Nat = () => zero
 const two: Nat = () => one
 const two1: Nat = () => 1
 
-const nat2Int: (n: Nat) => number = n => {
+const nat2Int: Nat => number = n => {
   if (n === null) {
     n()
     return 0