Skip to content

Instantly share code, notes, and snippets.

Avatar

Donald Pipowitch donaldpipowitch

View GitHub Profile
@donaldpipowitch
donaldpipowitch / README.md
Last active Dec 28, 2021
Type-safe query params in React with a "Hook Builder"
View README.md

Everyone loves type-safe APIs nowadays, but as far as I can tell query parameters are a blind spot to most people right now.

I create a hook which uses a builder pattern a while ago, which allows you to create type-safe query parameters. It is not very polished and contains some specific use cases, that's why I hesitated to share it. But as I successfully use it for a couple of month already and (afaik) no one came up with something similar so far, I wanted to share it.

How does it look like?

import * as pp from './page-params';

type FavoriteFood = 'pizza' | 'noodles' | 'wraps' | 'hot-dogs';
View use-timeout.ts
// it's like setTimeout as a hook, but with a small twist:
// you can make multiple subsequent calls and can increase or decrease
// the delay (e.g. useful to create polling like functionality)
type Options = {
delay: number;
multiplier?: number;
};
type State = {
@donaldpipowitch
donaldpipowitch / README.md
Last active Aug 12, 2021
Rewrite relative import paths with a codemod
View README.md

⚠️ This is for an internal project, but shared publicly as a reference for myself.

If you want to have a general introduction how to write such a codemod have a look at this Gist from me.

What to do?

Place the usage.js and prettiermod.js in the root of the project. Run:

$ pnpm add globby@^11.0.0 @babel/traverse
@donaldpipowitch
donaldpipowitch / README.md
Last active May 25, 2021
Create a codemod with Prettier and Babel
View README.md

Every now and then I'd like to apply a so called codemod to my a codebase. A codemod is a piece of code which modifies other code. Very often this is done by running some transformation on the abstract syntax tree (AST).

Whenever I need to do this I look for "What is the best way to apply a codemod on my TS code base right now?", because when I only do this every couple of month I either have forgotten about how to do it or tools have changed and my old way stopped working... or both. Surprisingly every time I search for that I found the existing tools bloated or quirky or not matching my workflow.

As I already use Babel to compile our source code I would like to create a Babel plugin which transforms my code. Sadly Babel alone is not good in preserving whitespace and formatting. Thankfully I use Prettier for that and because Prettier uses Babel internally I can create a Babel visitor to transform my source code.

The actually easiest and _most r

@donaldpipowitch
donaldpipowitch / get-nice-upper-bound.ts
Created Nov 13, 2020
Nice upper bound (e.g. for charts, ticks, scales)
View get-nice-upper-bound.ts
function getNiceUpperBound(value: number) {
const zeroCount = String(Math.round(value)).length - 1;
const factor = Math.pow(10, zeroCount);
return Math.ceil(value / factor) * factor;
}
const upperBound = getNiceUpperBound(3464634); // 4000000
View use-stable-memo.ts
import { DependencyList, useState, useEffect, useRef } from 'react';
// use this instead of useMemo of you need a stable value
// see https://twitter.com/0xca0a/status/1314326386555924480
export function useStableMemo<T>(factory: () => T, deps: DependencyList): T {
const [value, setValue] = useState<T>(factory);
const firstRun = useRef(true);
useEffect(
() => {
@donaldpipowitch
donaldpipowitch / use-location-state.ts
Created Jul 22, 2020
useLocationState: a glorified location.state for React Router as a hook
View use-location-state.ts
import { useState, useEffect } from 'react';
import { useLocation, useHistory } from 'react-router-dom';
import { useSessionStorage } from './use-storage'; // see https://gist.github.com/donaldpipowitch/7310d7b9e4b6d467134c425e8732adc6
type UseLocationStateOptions<T> = {
defaultValue?: T;
scope?: string;
filter?: (value: T) => boolean;
};
@donaldpipowitch
donaldpipowitch / mocked-storage.tsx
Last active Jul 22, 2020
useSessionStorage and useLocalStorage for easy mocking - similar to MemoryRouter in react-router, but for storage
View mocked-storage.tsx
import React, { FC, useMemo } from 'react';
import {
LocalStorageProvider,
SessionStorageProvider,
} from './use-storage';
// this is just a dumb mock of the storage interface
class MemoryStorage implements Storage {
private data: Record<string, string> = {};
@donaldpipowitch
donaldpipowitch / index.js
Created Jul 7, 2020
ESLint rule to check for round brackets in Jest `test` names. (Doesn't play nicely with --testNamePattern without escaping.)
View index.js
// @ts-check
/** @type {import("eslint").Rule.RuleModule} */
const rule = {
meta: {
docs: {
description: `If you use a Jest test name like "hello (world)" you can't run \`$ jest -t "hello (world)"\` to select this test.`,
},
fixable: 'code',
},
@donaldpipowitch
donaldpipowitch / index.js
Last active Jul 7, 2020
ESLint rule to check for duplicated exported names.
View index.js
// @ts-check
/** @type {import("eslint").Rule.RuleModule} */
const rule = {
meta: {
docs: {
description: `You can export a type and a value with the same name in the same file, but that confuses refactoring tools.`,
},
},
create(context) {