Skip to content

Instantly share code, notes, and snippets.

@JanMalch
Last active June 19, 2022 16:37
Show Gist options
  • Save JanMalch/b3ae0b27ae674168a8cbdf89c7cc2bb4 to your computer and use it in GitHub Desktop.
Save JanMalch/b3ae0b27ae674168a8cbdf89c7cc2bb4 to your computer and use it in GitHub Desktop.
TypeScript helper for refactorings
export interface Experiment<T> {
label: string;
use: () => T;
try: () => T;
predicate?: (a: T, b: T) => boolean;
}
function measure<T>(callback: () => T) {
const start = performance.now();
const result = callback();
const end = performance.now();
const time = (end - start)
return { result, time };
}
const i = (x: boolean | undefined) => x === true ? '✔️' : '❌';
function logEquality(a: any, b: any, predicate?: (a: any, b: any) => boolean) {
const equals = a == b;
const strictEquals = a === b;
const jsonEquals = JSON.stringify(a) == JSON.stringify(b);
const predicateEquals = predicate != null ? predicate(a, b) : undefined;
let result, label;
if (predicate != null) {
result = predicateEquals;
label = 'predicate'
} else if (typeof a === 'object') {
result = jsonEquals;
label = 'JSON.stringify equality'
} else {
result = strictEquals;
label = 'strict equality'
}
console.groupCollapsed(i(result) + ' ' + label)
if (predicateEquals != null) {
console.log(i(predicateEquals), 'predicate (', a, ',', b, ')')
}
console.log(i(equals), a, '===', b);
console.log(i(strictEquals), a, '==', b);
console.log(i(jsonEquals), JSON.stringify(a), '===', JSON.stringify(b), '(via JSON.stringify)');
console.groupEnd();
}
function runAndLogTimes<T>(experiment: Experiment<T>) {
const { result: useResult, time: useTime } = measure(() => experiment.use());
const { result: tryResult, time: tryTime } = measure(() => experiment.try());
const diff = useTime - tryTime;
const pct = (100 * diff / useTime).toFixed(0) + '%';
if (diff >= 0) {
console.groupCollapsed(`✔️ ${pct} faster`)
} else {
console.groupCollapsed(`❌ ${pct} slower`)
}
console.log('use ⏱️ ' + useTime + 'ms')
console.log('try ⏱️ ' + tryTime + 'ms')
console.log('diff ⏱️ ' + diff + 'ms')
console.groupEnd();
return { useResult, tryResult };
}
export function experiment<T>(experiment: Experiment<T>): T {
console.group('[Experiment] ' + experiment.label);
const { useResult, tryResult } = runAndLogTimes(experiment);
logEquality(tryResult, useResult, experiment.predicate)
console.groupEnd();
return useResult;
}

Usage

function sum(array: number[]): number {
    let result = 0;
    for (let i = 0; i < array.length; i++) {
        result += array[i];
    }
    return result;
}

const input = Array(1000).fill(0).map((_, i) => i);
const result = experiment({
    label: 'sum refactoring',
    use: () => sum(input),
    try: () => input.reduce((acc, val) => acc + val)
});
// result === sum(input)

Console output

[Experiment] sum refactoring
  ❌ -23% slower
    use  ⏱️ 0.06499991286545992ms
    try  ⏱️ 0.05000003147870302ms
    diff ⏱️ -0.014999881386756897ms
  ✔️ strict equality
    ✔️ 499500 === 499500
    ✔️ 499500 == 499500
    ✔️ 499500 === 499500 (via JSON.stringify)

This function is inspired by GitHub's Scientist!.

Please note that it's better to check your refactorings with unit tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment