Skip to content

Instantly share code, notes, and snippets.

View sstur's full-sized avatar

Simon Sturmer sstur

View GitHub Profile
from asyncio import Queue
from typing import Callable, TypeVar, Generic, AsyncIterable
T = TypeVar("T")
class EventEmitter(Generic[T]):
listeners: set[Callable[[T], None]] = set()
type Result<T> = [data: T, error: undefined] | [data: undefined, error: Error];
export function noThrow<Args extends Array<unknown>, T>(
fn: (...args: Args) => Promise<T>,
): (...args: Args) => Promise<Result<T>> {
return async (...args) => {
try {
const data = await fn(...args);
return [data, undefined];
} catch (e) {
@sstur
sstur / upload.ts
Last active January 9, 2023 08:05
type ReqInit = {
method?: 'PUT' | 'POST';
headers?: HeadersInit;
body: Blob | BufferSource | FormData | URLSearchParams | string;
signal?: AbortSignal;
onProgress?: (bytesLoaded: number, bytesTotal: number) => void;
};
export function upload(url: string, init: ReqInit) {
const { signal, onProgress, body } = init;

Polyfill ReadableStream making it always an async iterator:

ReadableStream.prototype[Symbol.asyncIterator] = function() {
  const reader = this.getReader();
  return {
    next: () => reader.read(),
    return: () => {
      reader.releaseLock();
    },
 };
import { useRef, useEffect, useCallback } from 'react';
export function useGetLatestValue<T>(value: T): () => T {
const valueRef = useRef(value);
useEffect(() => {
valueRef.current = value;
}, [value]);
return useCallback(() => valueRef.current, []);
}
function createErrorSubclass<T = string>(
name: string,
getMessage: (param: T | undefined) => string | undefined = (input) =>
input === undefined ? undefined : String(input),
ErrorClass: new () => Error = Error,
) {
if (!name.endsWith('Error')) {
throw new Error(`Invalid name "${name}"`);
}
return Object.defineProperties(
import crypto from 'crypto';
export function getRandomBytes(numBytes: number): Promise<Buffer> {
return new Promise((resolve, reject) => {
crypto.randomBytes(numBytes, (error, result) => {
error ? reject(error) : resolve(result);
});
});
}
import 'react-native';
import React from 'react';
import App from '../App';
// Note: test renderer must be required after react-native.
import { createRenderer } from 'react-test-renderer/shallow';
it('should render correctly', () => {
let renderer = createRenderer();
renderer.render(<App />);
import { useEffect, useState } from 'react';
let loadedScripts: Map<string, Promise<null>> = new Map();
export default function useScript(src: string) {
let [isLoaded, setLoaded] = useState(false);
useEffect(() => {
let promise = loadedScripts.get(src) || loadScript(src);
promise.then(() => {
setLoaded(true);
import { useCallback, useState, useRef } from 'react';
export function useDebounce<T>(initialValue: T, ms: number) {
let [value, setValue] = useState(initialValue);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let timeout = useRef<any>();
let debouncedSetter = useCallback(
(newValue: T) => {
clearTimeout(timeout.current);
timeout.current = setTimeout(() => {