Intro
- flow ๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ์คํํฑํ ํ์ ๋ค์ ์ฒดํฌํด์ฃผ๋ ๋๊ตฌ์ด๋ค.
- flow ๋ ์ฝ๋๊ฐ ๋ณ๊ฒฝ๋๋ ๋์ ๋น ๋ฅธ ํผ๋๋ฐฑ์ ์ค๋๋ค.
- flow ๋ ํ์ ์ ์ถ๋ก ํ ์ ์์ต๋๋ค.
install
-
๋ฐ๋ฒจ์ ์ด์ฉํด์ flow ์ ํ์ ๋ณํ์์ผ์ค์ผ ํ๋ค.
npm install --save-dev babel-cli babel-preset-flow
- ๋ง์ฝ ๋ฆฌ์ํธ๋ฅผ ์ฌ์ฉํด์ babel-preset-react๋ฅผ ์ฌ์ฉํ๋ค๋ฉด bable-preset-flow๋ ๋ณ๋๋ก ์ค์นํ ํ์๊ฐ ์๋ค.
-
.babelrc ์ preset ์์ฑ์ flow ์์ฑ
{ "preset": ["flow"] }
- ์ด ์ญ์๋ react๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด react๋ง ์ ์ด์ฃผ๋ฉด ๋๋ค.
-
flow ์ค์น
npm install -g flow-bin npm install --save-dev flow-bin
-
flow init
- flow init ์ ํ๊ฒ ๋๋ฉด .flowconfig ํ์ผ์ด ์์ฑ.
- .flowconfig์์ flow์ ์ฌ๋ฌ๊ฐ์ง config ์ค์ ์ ํ ์ ์์.
- ํํ์ด์ง ์ฐธ์กฐ! https://flow.org/en/docs/config/
- flow ๋ช ๋ น์ด๋ฅผ ์ฐจ๊ธฐ ๋๋ฉด ํด๋น ํ๋ก์ ํธ์ ํ์ ๋ค์ ์ฒดํฌ
์์ฝ
- flow init ์ผ๋ก ํ๋ก์ ํธ๋ฅผ init
- flow ๋ช ๋ น์ผ๋ก Flow background ํ๋ก์ธ์ค๋ฅผ ์คํ
- ๊ฐ ํ์ผ์๋จ์ "// @flow" ์ ๊ธฐ์ ํ๋ฏ๋ก์จ flow๊ฐ ๋ชจ๋ํฐ๋ง์ ํ ์ ์๊ฒ ์ ์
- flow code ์์ฑ
- flow error type ์ฒดํฌ
Type๋ค
-
primitive types
- ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ์์ํ์ ์ ์ ์
- ๋ฆฌํฐ๋ด ๊ฐ์ ํ์ ์ ์๋ฌธ์๋ก ์ ์
- object๋ก wrapper ํ๊ฒ๋ค์ capitalized ๋ก ์ ์
function method(x: number){} function method(x: Number){}
- Boolean , String, Number, null , undefined(flow๋ void๋ก ์ ์ ) , Symblos ( ์์ง flow๊ฐ ์ง์์ํจ )
-
Mixed types
- type์ ์์ ์์๋ ์ฌ์ฉํ๋ค.
- ํ๋ก๊ทธ๋จ๋ค์ ์ฌ๋ฌ๊ฐ์ง ๋ค๋ฅธ ํ์ ์ ์ข ๋ฅ๋ฅผ ์ง๋์ ์๋ค.
- mixed ํ์ ์ ์๋ฌด ํ์ ์ด๋ ๋ฐ์ ์ ์๋ค.
- mixed๋ ์๋ฌด๊ฑฐ๋ ๋ฐ์ ์ ์์ง๋ง mixed ์ ํ์ ๊ฐ์ ์ฌ์ฉํ๋ ค๊ณ ํ๋ค๋ฉด ์ค์ ์ ํ์ด ๋ฌด์์ธ์ง ์์๋ด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋ฌ๋ฅผ ๋ด๋ฟ๋๋ค.
function user(value: mixed) { return "" + value // error } function user(value: mixed) { if( typeof value === "string" ){ return "" + value // works!!! } }
-
any types
- mixed ์ ํ๊ฐ๋ ค ํ์ง ๋ง์ธ์.
- any ์์ฒด๋ ์๋ฒฝํ๊ฒ ์์ ํ์ง ์์ต๋๋ค. ์ด๋๋๋ ์๋ฌ๋ฅผ ๋ด๋ฟ์ง ์์ต๋๋ค.
- ๊ทธ๋์ any๋ก type์ ์ง์ ํ์ ๊ฒฝ์ฐ์๋ ๊ฐ๋ฅํ ๋นจ๋ฆฌ ๋ค๋ฅธ ํ์ ์ผ๋ก casting์ ํด์ผ ํฉ๋๋ค.
-
maybe types
- typing value๊ฐ ์์์๋ ์๊ตฌ ์์์๋ ์์๋ ์ฌ์ฉํ๋ค.
- ์๋ฅผ ๋ค์ด ?number ๋ผ๊ณ ํ์ ์ ์ง์ ํ๋ฉด ๋ฐ์ ์ ์๋ ํ์ ์ number , null , undefined ํ์ ๋ง์ ๋ฐ์ ์ ์๋ค.
-
variable types
- ๋ณ์๋ฅผ ์ ์ธํ ๋ ํ์ ์ ์ถ๊ฐํ๋ค.
- javascript ๋ณ์ ์ ์ธ ๋ฐฉ์์ const , let , var ๋ฐฉ์์ด ์๋ค.
- flow๋ ๋ ๊ทธ๋ฃน์ผ๋ก ๋๋๋ค ์ฌ ํ ๋น์ด ๊ฐ๋ฅํ์ง ( let, var ) ๊ฐ๋ฅํ์ง ์์์ง ( const )
var fooVar: number = 2; let barLet: number = 2; const bar: number = 2; fooVar = "3" // error
-
function types
- ํจ์๋ 2๊ฐ์ง ์ฅ์์ type์ ์ง์ ํ ์ ์๋ค. ํ๋๋ ๋งค๊ฐ๋ณ์ ( input ) ๋๋จธ์ง ํ๊ณณ์ return value ( output ) ์ด๋ค.
function concat(a: string , b: string): string { return a+b; } let method = (str: string , bool?: boolean, ...args: Array<number>) => { } // ํจ์ ํ์ ์ ์์ ์ง์ ํ ์ ์๋ค. type merlin = { ho: (str: string) => void, hoing: (string , boolean | void , Array<number>) => void, // ํ๋ผ๋ฏธํฐ ๋ช ์ ์๋ตํ ์๋ ์๋ค. } // ์ฝ๋ฐฑ์ ๋ํ๊ฒ๋ ์ง์ ํ ์ ์๋ค. function method(cb: (error: Error | null , value: string | null) => void){ }
- function ์ this์ ๊ฒฝ์ฐ์๋ ํด๋น function์ ์คํํ context๋ฅผ ์ฒดํฌํ๋ค.
- ์ ์ด ํจ์์ ๋ํด์๋ ๋ฆฌํด๊ฐ ๋ค์์ %checks ๋ผ๊ณ ์ ์ด์ฃผ์ง ์์ผ๋ฉด ์๋ฌ๋ฅผ ๋ฟ๋๋ค.
function truty(a,b):boolean %checks { return !!a && !!b; } function merlin(){ if(truty(a,b)){ } }
- ๋ง์ฝ ๋งค๊ฐ๋ณ์๋ก ์ข๋ ์ ์ฐํ function์ ๋ฐ์ผ๋ ค๋ฉด () => mixed ๋ฅผ ์ฌ์ฉํ๋ค.
function method(func: () => mixed){ }
- ๋ง์ฝ ํ์ ์ฒดํฌ๋ฅผ ํผํ ํ์์ฑ์ด ๋๋ผ๋ฉด์ any ๋ฐฉ๋ฒ์ ์ฌ์ฉ ํ์ง ์์ผ๋ ค๋ฉด Function ์ ํ์ ์ผ๋ก ์ฌ์ฉํ๋ฉด ๋๋ค. ํ์ง๋ง ์ด ๋ฐฉ๋ฒ์ ์์ ํ์ง ์๊ณ ํผํด์ผํ ๋ฐฉ๋ฒ์ด๋ค.
์๋์ ๊ฐ์ ์ฝ๋์์ ์๋ฌ๋ฅผ ๋ด๋ฟ์ง ์๋๋ค.
function method(func: Function){ func(1,2); //works func("1","2"); //works func({},[]) //works } method(function(a: number, b: number){ return a+b; })
-
Object types
var obj1: { foo: number, bar: boolean, baz: string } = { foo: 1, bar: true, baz: "abc" } var obj: { foo? : boolean} = {}; obj.foo = true // works obj.foo = "abc" // error
- value ์ type์ ์ค์ ํ ๋์๋ optional properties๊ฐ void ์ ์๋ต์ ์ฌ์ฉํ ์ ์๊ฒ ํ๋ค. ๋ค๋ง null ๊ฐ์ ์๋ฌ๋ฅผ ๋ธ๋ค.
// foo ์ null ์ ์ ํ ํ๋ฉด error๊ฐ ๋ฌ๋ค. function acceptsObject(value: {foo? : string}){ // ... }
- sealed object์ ๊ฒฝ์ฐ์๋ ์๋ ๊ฐ์ ์ถ๊ฐ ํ๋ ค๋ฉด ์๋ฌ๋ฅผ ๋ฟ๋๋ค.
- unsealed object์ ๊ฒฝ์ฐ์๋ ์๋ก์ด ๊ฐ์ ์ถ๊ฐํด๋ ํ๋ฝํ๋ค.
var obj = { foo: 1 } obj.bar = true; //error obj.baz = "abc"; //error
- ์กฐ๊ฑด๋ฌธ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ํ๋กํผํฐ์ ๊ฐ์ด ์๋ค๋ฉด ์๋์ฒ๋ผ ํด์ค์ผ ํ๋ค.
- sealed object ๋ ํ๋กํผํฐ๋ฅผ ์ถ๊ฐ ํ ์ ์๋ค.
var val3: boolean | string = obj.prop;
- unsealed object ์ ์์ง๋ชปํ๋ ํ๋กํผํฐ๋ฅผ ์ ํด์ง ํ์ ์ ํ ๋นํ๋ ๊ฒ์ ์์ ํ์ง ๋ชปํ๋ค.
- exact ํ obect๋ฅผ ๋ง๋ค๊ณ ์ถ๋ค๋ฉด {| |} ๋ฅผ ์ฌ์ฉํ๋ค.
var foo: {| foo: string |} = { foo: "Hello", bar: "World!" }; // Error!
- flow๋ ๊ธฐ๋ณธ object type์์ ์ถ๊ฐ ์์ฑ๋ค์ ์์ ํ๊ฒ ์๊ฐํ๋ค. ์ด๊ฒ์ "width subtyping" ์ด๋ผ ํ๋ค.
function method(obj: { foo: string }) { // ... } method({ foo: "test", // Works! bar: 42 // Works! });
-
array types
- array ํ์
์ Array
์ผ๋ก ์ฌ์ฉํ๊ณ Type ์ฅ์์ ๋ฐฐ์ด์ ์์ ํ์ ์ ์ ์ ํ ์ ์๋ค.
let arr: Array<number> = [1, 2, 3]; let arr2: Array<string> = ["1", "2", "3"]
- ์ถ์ฝํ์ผ๋ก Type[] ์ผ๋ก ์ถ์ฝํ ์๋ ์๋ค.
let arr: number[] = [0, 1, 2, 3];
- ?Type[] ๋ ?Array
์ ๊ฐ๊ณ Array<?T>๋ (?Type)[] ๊ณผ ๊ฐ๋ค.
// ์ด๋ถ๋ถ์ ์ซ์๋ก ๋ ๋ฐฐ์ด์ด๊ฑฐ๋ , null , undefined let arr1: ?number[] = null; // Works! let arr2: ?number[] = [1, 2]; // Works! let arr3: ?number[] = [null]; // Error! // ์ด๋ถ๋ถ์ ๋ฐฐ์ด์ด๋ฉด์ ๋ฐฐ์ด ์์ element๋ค์ด ์ซ์์ด๊ฑฐ๋ , null , undefined ๋๊ฑฐ let arr1: (?number)[] = null; // Error! let arr2: (?number)[] = [1, 2]; // Works! let arr3: (?number)[] = [null]; // Works!
- array type์ ์์ ํ๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
let array: Array<number> = [0, 1, 2]; let value: number | void = array[1]; if( value !== undefined ){ // number }
- array ํ์
์ Array
-
tuple types
let tuple1: [number] = [1]; let tuple2: [number, boolean] = [1, true]; let tuple3: [number, boolean, string] = [1, true, "three"];
- mutating ํ Array method๋ฅผ tuples type์ ์ฌ์ฉํ์ง ์๋๋ค.
- tuples๋ array type๊ณผ match ์ํค์ง ์๋๋ค.
- ๊ฐ์ tuples ํ์ ์ด๋ผ๋ ๊ฐ์ length ์ฌ์ผ ํ๋ค.
-
class types
- flow ์์์ javascript classes ๋ ๊ฐ๊ณผ ํ์ 2๊ฐ์ง๋ก ์๋ํ๋ค.
class MyClass { // ... prop: number; method(value: string): number { this.prop = 42; // ์ด๊ฑธ ์ฌ์ฉํ๋ ค๋ฉด ์์ ์ฒ๋ผ ํ๋์ ๋ํ ํ์ ์ ์ค์ ํด์ผ ํ๋ค. } } let myInstance: MyClass = new MyClass();
- classes๋ ์์ ๋ง์ generics๋ฅผ ๊ฐ์ง์ ์๋ค.
// @flow class MyClass<A, B, C> { constructor(arg1: A, arg2: B, arg3: C) { // ... } } var val: MyClass<number, boolean, string> = new MyClass(1, true, 'three');
-
Type aliases
- ๋ณต์กํ ํ์ ๋ค์ ๋ค์ํ ์ฅ์์์ ์ฌ์ฉํ๊ณ ์ถ์๋ flow๋ type alias๋ฅผ ์ฌ์ฉํ๋ค.
type MyObject = { foo: number, var: boolean, baz: string }
- generics ๋ฅผ ํ์ฉํด์ ์ ์ํ ์๋ ์๋ค.
type MyObject<A, B, C> = { foo: A, bar: B, baz: C, }; var val: MyObject<number, boolean, string> = { foo: 1, bar: true, baz: 'three', };
-
Opaque Type Aliases
- Opaque type aliases๋ ์ด ํ์ ์ด ์ ์๋ ํ์ผ ์ธ๋ถ์ ์๋ ๋ค๋ฅธ ํ์ผ๋ค์์ ์ ๊ทผ์ ํ์ฉํ์ง ์๋๋ค.
- ์ด ํ์ ์ ์ ์ธ๋ ๊ณณ ์ด๋์๋ ์ฌ์ฉ๋ ์ ์๋ type aliases์ ๋์ผํ๊ฒ ์๋ํ๋ค.
opaque type ID = string; function identity(x: ID): ID { return x; } export type {ID};
- ๋ํ optionallyํ๊ฒ ์ ์ฝ์กฐ๊ฑด subtyping์ ์ถ๊ฐํ ์ ์๋ค.
// Opaque type alias syntax opaque type Alias = Type; opaque type Alias: SuperType = Type; opaque type ID: string = string;
- import ํ opaque type์ ์ธ๋ถ์์ ์ฌ์ฉํ ์ ์๋ค. ๋ง์น nomial type ์ฒ๋ผ ํ๋ํ๋ค.
- c++ , java , swift๋ nomial type ์์คํ ์ ์ฌ์ฉํ๋ค.
- nominal type system ์ด๋ ํ์ ์ ๊ตฌ์กฐ๊ฐ ๊ฐ๋๋ผ๋ ์ด๋ฆ์ด ๋ค๋ฅด๋ฉด ์๋ฌ๋ฅผ ๋ฟ๋๋ค.
// exports.js export opaque type NumberAlias = number; // imports.js import type {NumberAlias} from './exports'; (0: NumberAlias) // Error: 0 is not a NumberAlias! function convert(x: NumberAlias): number { return x; // Error: x is not a number! }
- opaque type alias ์ subtyping constraint๋ฅผ ์ถ๊ฐํ ๋ ์ฐ๋ฆฌ๋ super type์ผ๋ก ์ฌ์ฉ๋ opaque type์ ์ ์ธ๋ ํ์ผ ๋ฐ์์ ์ฌ์ฉํ ์ ์๋ค.
//exports.js export opaque type ID: string = string; //import.js import type {ID} from './exports.js'; function formatID(x: ID): string { return "ID: " + x; // works } function toID(x: string): ID { return x; }
- subtyping constraint๋ฅผ ํจ๊ป ์ฐ๋ opaque type alias ๋ฅผ ๋ง๋ค๋ ํ์ ์ค์ ์ ๋ฐ๋์ super type positiona์ ์ค์ ๋ ํ์ ์ ์ง๋๊ณ ์์ด์ผ ํ๋ค.
opaque type Bad: string = number; // Error: number is not a subtype of string opaque type Good: {x: string} = {x: string, y: number};
-
Interface Types
- classes flow type ์ ๊ฒฝ์ฐ์๋ nominal typed ์ด๋ค. ๋ค์๋งํด์ ๊ฐ์ ์์ฑ๊ณผ ๊ฐ์ ๋ฉ์๋๊ฐ ์์ด๋ ์๋ก ์ด๋ฆ์ด ๋ค๋ฅธ classes type์ ํ๊ณณ์์ ๋ค๋ฅธ๊ณณ์ผ๋ก ์ฌ์ฉ์ด ๋ถ๊ฐํ๋ค.
- ๋์ ์. interface ๋ก ๊ธฐ๋ ๋๋ class structure ๋ฅผ ์ ์ธํ ์ ์๋ค.
interface Serializable { serialize(): string; } class Foo { serialize() { return '[Foo]'; } } class Bar { serialize() { return '[Bar]'; } } const foo: Serializable = new Foo(); // Works! const bar: Serializable = new Bar(); // Works!
- implements ๊ตฌ๋ฌธ์ ์ฌ์ฉํด์ flow ์๊ฒ ์ด ์ธํฐํ์ด์ค์ ๋งค์นญ๋๋ ํด๋์ค๋ฅผ ์ํ๋ค๋ ๊ฒ์ ๋งํด์ค์๊ฐ ์๋ค. ์ด๊ฒ์ ๋ค๋ฅธ ์ฌ๋์ด ํด๋์ค๋ฅผ ์ฝ๊ฒ ๋ณํ๊ฒ ๋ง๋ค์ง ๋ชปํ๋๋ก ๋ณดํธํ ์ ์๋ค.
- ๋ฉํฐ๋ก 2๊ฐ ์ด์๋ ์ค์ ๊ฐ๋ฅ
// @flow interface Serializable { serialize(): string; } class Foo implements Serializable { serialize() { return '[Foo]'; } // Works! } class Bar implements Serializable { // $ExpectError serialize() { return 42; } // Error! }
- ์ธํฐํ์ด์ค syntax๋ ์๋์ ๊ฐ๋ค.
interface MyInterface { method(value: string): number; property: string; property?: string; [key: string]: number; }
-
์ธํฐํ์ด์ค๋ ๋ค๋ฅธ ํ์ ๊ณผ ๊ฐ์ด generics๋ฅผ ์ฌ์ฉํ ์ ์๊ณ ํ๋กํผํฐ์ read-only ์ write-only๋ฅผ ์ค์ ํ ์์๋ค.
interface MyInterface<A, B, C> { foo: A; bar: B; baz: C; } interface MyInterface { +covariant: number // read-only -contravariant: number; // write-only } interface Invariant { property: number } interface Contravariant { -writeOnly: number } function method1( value: Invariant) { value.property; // works value.property = 3.14 // works } funtion method2 ( value: contravariant) { value.property; // error value.writeOnly = 3.14 // works!! }
- write-only ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ๋ pass๋ฅผ ์งํํ๋ค.
interface Contravariant { -writeOnly: number } var numberOrString = Math.random() > 0.5? 42 : 'forty-two'; var value2: Contravariant = { writeOnly: numberOrString };
-
Generic Types
- generic์ ์ถ์์ ์ผ๋ก ํ์ ์ ์ง์ ํ ์ ์๋ ๋ฐฉ๋ฒ์ด๋ค.
- generic์ function , function types , classes , type aliases , interface์ ์ฌ์ฉ๋ ์ ์๋ค.
- function ์ฌ์ฉ
function identity<T>(value: T): T { return value; } <T>(param: T) => T
- classes ์ฌ์ฉ
class Item<T> { //... } class Item<T> { prop: T; constructor(param: T) { this.prop = param; } method(): T { return this.prop } }
- many generics as you need
function identity<One, Two, Three>(one: One, two: Two, three: Three) { }
- generic ํ์ ์ ๋ง ๊ทธ๋๋ก "unknown" type์ด๋ค. ํ์ง๋ง ํจ์ ์์์ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด ์๋ฌ๋ฅผ ๋ฟ๋๋ค.
function logFoo<T>(obj: T): T { console.log(obj.foo); // error return obj } // ์ ํํ ํ์ ์ ์ฐ๊ธฐ ์ํด ๋ถ๊ธฐ๋ฅผ ์ณ์ผ ํ๋ค. function logFoo<T>(obj: T): T { if (obj && obj.foo) { console.log(obj.foo); // Works. } return obj; } // ๋๋ ํ์ ์ ์ง์ ํ๋ค. function logFoo<T: {foo: string}>(obj: T): T { console.log(obj.foo); return obj; }
- flow๊ฒฝ์ฐ ํ๋์ ํ์ ์ ๋ค๋ฅธ๊ณณ์ผ๋ก ์ ๋ฌํ ๋ original type์ ์์ด๋ฒ๋ฆฐ๋ค. ๊ทธ๋์ ๊ตฌ์ฒด์ ์ธ ํ์ ์ ๋ ๊ตฌ์ฒด์ ์ธ ํ์ ์ผ๋ก ์ ๋ฌํ ๋ flow ๋ "forget" ๋๋ค. ๊ทธ๊ฒ์ ํ๋ ๊ตฌ์ฒด์ ์ด์๋ ๊ฒ์ด๋ค.
function identity<T>(val: T): T{ retur val } let foo: 'foo' = 'foo'; // works // identity ํธ์ถํ ๋ ๊ตฌ์ฒด์ ์ธ string์ด ์ ์ ๋ฌ์ง๋ง ํธ์ถ ์ดํ์ original type์ ์์ด๋ฒ๋ฆผ.. ๊ทธ๋์ ์๋ํ ์ ์๋ค. let bar: 'bar' = identity('bar'); // works
- generic์ ํจ์์ arguments ์ฒ๋ผ ํ์ ์ ์ง์ ํ ์ ์๋ค.
type Item<T> = { prop: T, } let item: Item<string> { prop: "value" }
- classes ๋ฒ์ ผ
class Item<T> { prop: T; constructor(param: T) { this.prop = param; } } let item: Item<number> = new Item(42); let item: Item = new Item(42); // error;
- type aliases ๋ฒ์ ผ
type Item<T> = { prop: T, } let item1: Item<number> = {prop: 42} let item2: Item = {prop: 42} // error
- interface ๋ฒ์ ผ
interface HasProp<T> { prop: T, } class Item { prop: string } (Item.prototype: HasProp<string>); // works (Item.prototype: HasProp) // error
- default ๊ฐ๋ ์ค์ ํ ์์๋ค.
type Item<T: number = 1> = { prop: T, }; let foo: Item<> = { prop: 1 }; let bar: Item<2> = { prop: 2 };
-
Union types
- ์ฌ๋ฌ๊ฐ์ง ํ์ ์ ๋ฐ๊ณ ์ถ๋ค๋ฉด Union types๋ฅผ ์ธ์ ์๋ค.
- syntax๋ ์๋์ ๊ฐ๋ค.
Type1 | Type2 | ... | TypeN
- ์ฌ๋ฌ ํ์ ์ (union types)์ ์ฌ์ฉํ๋ค๋ฉด ์ฐ๋ฆฌ๋ ๊ทธ๋ค ํ์ ์ค ํ๋๋ง์ ๋ค๋ค์ผ ํ๋ค.
function toStringPrimitives(value: number | boolean | string): string { // Error! if (typeof value === 'number') { return String(value); } else if (typeof value === 'boolean') { return String(value); } }
- ์ฌ๋ฌํ์ ์ค ํ๊ฐ์ง ํ์ ๋ง ๋ค๋ฃจ๊ณ ์ถ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ํฉ๋๋ค.
function toStringPrimitives(value: number | boolean | string) { if (typeof value === 'number') { return value.toLocaleString([], { maximumSignificantDigits: 3 }); // Works! } // ... }
- ๋ง์ฝ ์ฐ๋ฆฌ๊ฐ ๋๊ฐ์ง์ object types๋ค์ union type์ผ๋ก ์์ฑํ๋ค๋ฉด flow ๋ ๋ object type ์ ๋ค์ด์๋ success property ๋ฅผ base๋ก ์ฌ์ฉํ์ฌ ์์๋ผ์ ์๋ค.
type Success = {success: true, value: boolean} type Fail = {success: false, error: string} type Response = Success | Fail; function handleResponse(response: Response) { if( response.success ){ var value: boolean = response.value // work } else { var error: boolean = response.error // work } }
- union type์ ์์ฒ๋ผ ๋ถ๋ฆฌํด์ ์ฌ์ฉํ๋ ค๋ฉด ์ ํํ ํ์ ๊ณผ ํจ๊ป ์ฌ์ฉํด์ผ ํ๋ค. disjoint unions type์ ๊ฐ object์์ ํ๊ฐ์ง ํ๋กํผํฐ๋ฅผ ๊ตฌ๋ณ๋ก ์ฌ์ฉํ๋ค. ๋ฐ๋ผ์ ๊ตฌ๋ณ ํ ์ ์๋ ํ๋กํผํฐ๊ฐ ์๋ค๋ฉด ์๋ฌ๋ฅผ ๋ฟ๊ฒ ๋๋ค. ์ด๊ฒ์ flow๊ฐ object type์ ๋ ํ์ฅ ๊ฐ๋ฅํ ๊ฐ์ผ๋ก ๋ณด๊ธฐ ๋๋ฌธ์ด๋ค.
- ์ ์ฌ์ฉํด์ผ ๊ฒ ๋ค๋ฉด ์๋์ฒ๋ผ
type Success = {| success: true, value: boolean |}; type Failed = {| error: true, message: string |}; type Response = Success | Failed; function handleResponse(response: Response) { if (response.success) { var value: boolean = response.value; } else { var message: string = response.message; } }
-
Intersection Types
- & ๋ก ์ฐ๊ฒฐ๋ ํ์ ๋ค ์ด๊ฒ๋ค์ ๋ชจ๋๋ฅผ ๋ง์กฑํด์ผ ํ๋ค.
type A = { a: number }; type B = { b: boolean }; type C = { c: string }; function method(value: A & B & C) {} // ExpectError method({ a: 1 }); // Error! // ExpectError method({ a: 1, b: true }); // Error! method({ a: 1, b: true, c: 'three' }); // Works!
-
Typeof Types
- ์๋ฐ์คํฌ๋ฆฝํธ์ typeof ์ฐ์ฐ์์์ ๋ฆฌํด๋๋ ๊ฐ์ผ๋ก ํ์ ์ ์ ์ํ๋ค.
let num1 = 42; let num2: typeof num1 = 3.14; // Works! // $ExpectError let num3: typeof num1 = 'world'; // Error!
-
Type Casting Expressions
- ํจ์๋ ๋ณ์๋ฅผ ์ ์ธํ์ง ์๊ณ ํ์ ์ ์ง์ ํ๊ณ ์ถ์ ๋๊ฐ ์์ ๊ฒ์ ๋๋ค. ์ด๋ flow๋ inline type cast expression ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
(value: Type) let val = (value: Type) let obj = { prop: (value: Type)} let arr = ([(value: Type),(value: Type)]: Array<Type>)
- ์ ์ธ ๋ฟ๋ง ์๋๋ผ ํ ๋น๋ ํ ์ ์๋ค.
let value = 42; (value: 42); // Works! (value: number); // Works! // 42 ํ ๋น ๋ฐ type number let newValue = (value: number); // $ExpectError (newValue: 42); // Error! (newValue: number); // Works!
- ๋ค์ ์๋์ ๊ฐ์ด value ๋ฅผ any๋ก ์บ์คํ ํ๋ฉด, ๋๋ ์ํ๋ ์ด๋ค๊ฒ์ด๋ ํ์ ์ ์บ์คํ ํ ์ ์๋ค. ๋ค๋ง ์ด๊ฑด ๊ต์ฅ์ด ์์ ํ์ง ์๋ค.
let newValue = ((value: any): string);
- ํ์ง๋ง ํ์ ์ ์ง์ ํ๊ธฐ ์ด๋ ต๊ณ ๋ถ๊ฐ๋ฅํ ๋์๋ result์ ๋ฐ๋ผ์ ํ์ ์ด ์ ํด์ง๊ธธ ๋ฐ๋์ ์๋ค. ์๋ฅผ ๋ค์ด๋ณด์
// ์์ ๋ณต์ฌ function cloneObject(obj) { const clone = {}; Object.kets(obj).forEach(key => { clone[key] = obj[key]; }) // return clone; // ์ด๋ ๊ฒ ์ฌ์ฉ๋ ์ ์๋ค. return ((clone: any): typeof obj); }
- ๋ง์ฝ ์ฐ๋ฆฌ๊ฐ cloneObject ๋ฉ์๋๋ฅผ ์คํํ๊ธฐ์ ์ ๋ค์ด์ค๋ ์ธ์์ ํ์ ์ ๋จผ์ ์ ํ๋ค๋ฉด ์๋์ฒ๋ผ ์์ฑํ ๊ฒ์ด๋ค.
function cloneObject(obj: { [key: string]: mixed}){}
- ํ์ง๋ง ์ ์ฝ๋๋ ๋ฌธ์ ๊ฐ ์๋ค. ์ฐ๋ฆฌ์ typeof obj annotation ๋ํ ์๋ก์ด annotation์ ๊ฐ๊ธฐ์ ์ ์ฒด ๋ชฉ์ ์ ํ๊ดด์ํจ๋ค.
- ๊ทธ๋์ ์ฐ๋ฆฌ๋ function ์์ ์ฌ์ฉํ ํ์ ์ ๋ํด์ assertion ํด์ผํ๋ค.
function cloneObject(obj) { (obj: { [key: string]: mixed}); //... return ((clone: any): typeof obj); }
- ์ค์ง์ ์ธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค.
function cloneObject<T: { [key: string]: mixed }> (obj: T): $Shape<T> { //... }
-
Utility Types
- flow ๋ flow ์์ฒด๋ด์ utility types ๋ค์ ์ ๊ณตํ๋ค.
ํํ์ด์ง ์ฐธ๊ณ : https://flow.org/en/docs/types/utilities/