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 / awaiting-custom-thenable.ts
Last active June 17, 2020 13:26
Awaiting custom `Thenable<T>` in TypeScript
interface Thenable<T> {
then<U>(onResolve: (value: T) => U, onReject: (error: any) => Thenable<U>): Thenable<U>
then<U>(onResolve: (value: T) => Thenable<U>, onReject: (error: any) => Thenable<U>): Thenable<U>
}
const client: Thenable<string> = {
async then(resolve: (value: string) => Promise<string>, reject: (error: string) => Promise<string>) {
return Math.random() > 0.5
? resolve('Success!')
: reject('Failure!')
@karol-majewski
karol-majewski / easy-binary-search.ts
Last active July 7, 2020 13:20
Easy binary search in TypeScript
type Comparator<T> = (x: T, y: T) => Comparison;
enum Comparison {
LessThan = -1,
Equal = 0,
GreaterThan = 1,
}
function search<T>(array: T[], item: T, compare: Comparator<T>): number {
let [left, right] = [0, array.length - 1];
@karol-majewski
karol-majewski / depth-first-dom-traversal.ts
Created June 14, 2020 23:26
Depth-first traversal of a DOM subtree
function visit(node: Element, callback: (element: Element) => void): void {
callback(node);
Array
.from(node.children)
.forEach(child => visit(child, callback));
};
visit(document.body, console.log);
@karol-majewski
karol-majewski / overloading-curried-functions.ts
Created June 14, 2020 20:51
Overloading curried functions in TypeScript
function sum(x: number): (y: number) => number;
function sum(x: number, y: number): number;
function sum(x: number, y?: number): ((y: number) => number) | number {
if (y === undefined) {
return (y: number) => x + y;
}
return x + y;
// This also works:
@karol-majewski
karol-majewski / mapping-over-tuples.ts
Created June 13, 2020 00:25
Array.prototype.match overload that works for tuples
// 1. Let's define a tuple of country codes.
const countries: [string, string] = ["es", "ko"];
// 2. Good! We know the returned tuple will only have two elements.
const [spanish, korean, valyrian] =
countries.map(country => new Intl.DateTimeFormat(country));
// 3. We know `valyrian` doesn't exist!
valyrian.format(new Date());
@karol-majewski
karol-majewski / intersperse.ts
Last active June 18, 2020 08:28
Interspersing collections in TypeScript
type NonEmptyArray<T> = [T, ...T[]];
const hasElements = <T>(collection: T[]): collection is NonEmptyArray<T> =>
collection.length > 0;
const head = <T>(collection: NonEmptyArray<T>): T =>
collection['0'];
const tail = <T>(collection: T[]): T[] => {
const [_, ...tail] = collection;
@karol-majewski
karol-majewski / composition-vs-coupling.md
Last active May 24, 2020 23:22
What's the difference between composition and coupling?

I will use a contrived example.

The problem

We need to increment some numbers. Given an integer x, our function should return x + 1.

Coupling

Programmer 1 reads the requirements and creates the following implementation:

@karol-majewski
karol-majewski / serialize.ts
Created April 9, 2020 18:27
Make PUT and POST requests with fetch
type ContentType = 'application/x-www-form-urlencoded' | 'application/json';
/**
* POJO payloads used to make PUT and POST requests made with `fetch`
* need to be converted to a format `fetch` accepts first.
*/
export const serialize = (payload: object, type: ContentType): string => {
switch (type) {
case 'application/x-www-form-urlencoded':
return Object.entries(payload)
@karol-majewski
karol-majewski / css-in-js.ts
Created April 6, 2020 17:05
Managing CSS Custom Properties
declare class CSSPropertyManager<T> {
has<K extends keyof T>(property: K): asserts this is CSSPropertyManager<T & Required<T, K>;
get<K extends keyof T>(property: K): boolean;
set(property: keyof T, value: string): this;
}
const schema = {
'--width-1': string;
}
@karol-majewski
karol-majewski / cypress-gotchas.md
Created March 31, 2020 22:53
Things I wish I knew before I started writing Cypress tests

Cypress gotchas

Can I spy on a global method?

In theory, yes. Cypress documentation recommends adding spies in the onBeforeLoad phase.

cy.visit('/', {
 onBeforeLoad(win) {