Skip to content

Instantly share code, notes, and snippets.

@karol-majewski
Last active September 18, 2021 13:14
Show Gist options
  • Save karol-majewski/39ebb79602a38c3b0e5d79a0fcc80205 to your computer and use it in GitHub Desktop.
Save karol-majewski/39ebb79602a38c3b0e5d79a0fcc80205 to your computer and use it in GitHub Desktop.
Snippets used in my talk “Who Guards the Type Guards?” (https://www.youtube.com/watch?v=StyKp5dgN_Y)
/**
* A.K.A. type guard
*/
type Refinement<T, U extends T> = (candidate: T) => candidate is U;
function isString(candidate: unknown): candidate is string {
return typeof candidate === 'string';
}
interface Apple { species: 'Malus domestica' }
interface Cucumber { species: 'C. sativus' }
type Fruit = Apple | Cucumber;
/**
* Mixed items.
*/
declare const basket: Fruit[];
/**
* Apples only.
*/
let apples: Apple[];
apples = basket.filter((fruit): boolean => fruit.species === 'Malus domestica');
apples = basket.filter((fruit): fruit is Apple => fruit.species === 'Malus domestica');
export function isString(candidate: unknown): candidate is string {
return typeof candidate === 'number'; // 🤷‍♂️
}
import { some, none, getRefinement } from 'fp-ts/lib/Option'
const isString = getRefinement<unknown, string>(
(candidate) => typeof candidate === 'string'
? some(candidate)
: none
)
class Some<T> {
constructor(readonly value: T) {}
}
class None {}
type Option<T> = Some<T> | None;
function getRefinement<T, U extends T>(getOption: (candidate: T) => Option<U>): Refinement<T, U> {
return (candidate: T): candidate is U =>
getOption(candidate) instanceof Some;
}
import Refinement, { either } from 'refinements';
abstract class Fruit {
readonly species: string;
}
class Orange extends Fruit {
readonly species: 'orange';
}
class Mango extends Fruit {
readonly species: 'mango';
}
const isOrange: Refinement<Fruit, Orange> = Refinement.create(
fruit =>
fruit instanceof Orange
? Refinement.hit(fruit)
: Refinement.miss
);
const isMango: Refinement<Fruit, Mango> = Refinement.create(
fruit =>
fruit instanceof Mango
? Refinement.hit(fruit)
: Refinement.miss
);
const isJuicy = either(isOrange, isMango)
import Refinement, { not } from 'refinements';
type Stable = 'inherit' | 'initial' | 'revert' | 'unset';
type Prefixed = '-moz-initial';
type CSSProperty = Stable | Prefixed;
const isPrefixed = Refinement.create(
(property: CSSProperty) =>
property === '-moz-initial'
? Refinement.hit(property)
: Refinement.miss
);
const isStandard = not(isPrefixed);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment