# Refinements with Flow

`Integer = ( number, (n) => n % 1 === 0 )`

# The idea

`// myrefinement.js// privateclass IsR {}// publicexport type R = A & IsR;// publicexport function refinement(a: A): ?R {  return predicate(a) ? ((a: any): R) : null}`

# A first example, integers

`// integer.jsclass IsInteger {}export type Integer = number & IsInteger;export function integer(a: number): ?Integer {  return a % 1 === 0 ? ((a: any): Integer) : null}`
`import type { Integer } from './integer.js'import { integer } from './integer.js'function foo(n: number) { ... }function bar(n: Integer) { return n > 0 } // <= n is not boxedinteger(1.1) // => nullconst i = integer(1)if (typeof i === 'number') {  foo(i) // <= we can call foo because an integer is a number...  bar(i)}// ... but a number is not an integerbar(1) // <= error: number. This type is incompatible with isInteger`

# Polymorphic refinements

`// nonEmptyArray.jsclass IsNonEmptyArray {}export type NonEmptyArray<A> = Array<A> & IsNonEmptyArray;// polymorfic functionexport function nonEmptyArray<A>(a: Array<A>): ?NonEmptyArray<A> {  return a.length > 0 ? ((a: any): NonEmptyArray<A>) : null}`
`import type { NonEmptyArray } from './nonEmptyArray.js'import { nonEmptyArray } from './nonEmptyArray.js'function foo<A>(a: NonEmptyArray<A>) { ... }const a = nonEmptyArray([1, 2, 3])if (a) {  foo(a)}// foo([1, 2, 3]) // error`

# Drawbacks

`function foo(x: Object) { ... }const i = integer(1)if (typeof i === 'number') {  foo(i) // <= Flow doesn't complain}`

--

--

## More from gcanti

mathematician and rock climber

Love podcasts or audiobooks? Learn on the go with our new app.