Skip to content

Instantly share code, notes, and snippets.

View karol-majewski's full-sized avatar

Karol Majewski karol-majewski

View GitHub Profile
@karol-majewski
karol-majewski / logrocket.ts
Last active June 24, 2021 11:39
Using JavaScript Proxies with TypeScript
import LR from 'logrocket';
/**
* Fails silently if `LogRocket#init` throws.
*
* @see https://stackoverflow.com/a/43823282/10325032
*/
export const LogRocket = new Proxy(LR, {
get(target, property: keyof typeof LR, receiver) {
if (property === 'init') {
import React from 'react';
type DeferTypeInference<T> = [T][T extends any ? 0 : never];
interface Props<T extends string> {
themeMap: Record<T, any>
defaultTheme?: DeferTypeInference<T>;
}
class ThemeSwitcherProvider<T extends string> extends React.Component<Props<T>> { }
@karol-majewski
karol-majewski / solver.ts
Last active January 11, 2023 10:32
Filtering string literal types based on an affix in TypeScript
/**
* Challenge: given a list of icon names, find icons that exist in sizes 16x16px *and* 24x24px.
* This is an AND relationship, not an OR relationship.
*
* The solution should be: '16-hamburger' | '16-warning' | '24-hamburger' | '24-warning'.
*/
type IconName =
| '16-hamburger' // 👈🏻
| '16-warning' // 👈🏻
| '16-foo'
@karol-majewski
karol-majewski / problem.ts
Last active March 26, 2021 13:16
The difference in property binding order between TypeScript and Babel
class Foo {
constructor(public namespaces: string[]) {
this.namespaces = namespaces;
}
options = {
ns: this.namespaces
};
get opts() {
@karol-majewski
karol-majewski / memoize.ts
Last active May 24, 2021 23:14
Memoize a function based on a custom equality function (+ use case for unique symbol)
type AnyFunction = (...args: any[]) => any;
/**
* Creates a memoized function that preserves reference equality based on a predicate function.
*
* @param fn Function which return value will be memoized.
* @param isEqual Should return `true` when two objects are considered identical.
*
* @example
*
@karol-majewski
karol-majewski / promisify.ts
Created January 8, 2021 11:51
Promisify callback APIs using TypeScript leading rest elements in tuples (https://github.com/microsoft/TypeScript/pull/41544)
import * as fs from 'fs';
const promisify = <T>(fn: Promisifiable<T>) => (...args: DropLast<Parameters<typeof fn>>) =>
new Promise<T>((resolve, reject) => {
fn(...args, (err: Error | null, val: T) => (err ? reject(err) : resolve(val)));
});
async () => {
try {
const pkg: Buffer = await promisify(fs.readFile)('package.json');
declare global {
interface DOMRect extends DOMRectReadOnly {
/**
* @deprecated Doesn't work on legacy Edge. Use `left` instead.
*/
x: number;
/**
* @deprecated Doesn't work on legacy Edge. Use `right` instead.
*/
y: number;
@karol-majewski
karol-majewski / add.ts
Last active November 30, 2020 01:21
Type-level addition in TypeScript (2 methods)
interface Increments {
0: 1;
1: 2;
2: 3;
3: 4;
4: 5;
}
interface Decrements {
1: 0;
@karol-majewski
karol-majewski / withHover.ts
Created November 4, 2020 20:24
The simplest possible higher-order component in React
export function withHover<T>(WrappedComponent: React.ComponentType<T & Hoverable>): React.ComponentClass<T> {
return class extends React.Component<T> {
state = {
hover: false,
};
onMouseEnter: React.MouseEventHandler = () => {
this.setState({ hover: true });
};
@karol-majewski
karol-majewski / error-middleware.ts
Last active October 20, 2020 12:51
The simplest error handling middleware for Redux
import { Action, AnyAction, Middleware } from 'redux';
const errorMiddleware: Middleware =
store =>
next =>
(action: AnyAction) => {
if (action.error instanceof Error) {
store.dispatch({
type: '@@internal/EXCEPTION_THROWN',
payload: action.error.message,