Skip to content

Instantly share code, notes, and snippets.

View SandroMaglione's full-sized avatar
💡
Helping devs at typeonce.dev

Sandro Maglione SandroMaglione

💡
Helping devs at typeonce.dev
View GitHub Profile
@SandroMaglione
SandroMaglione / debounce-machine.ts
Created May 19, 2025 03:19
Input check debounce state machine using `xstate` ⏱️
const debounceMachine = setup({
types: {
events: {} as { type: "edit"; text: string },
},
actors: {
check: fromPromise(
// 👇 Use `signal` to abort the promise if the user starts typing
({ input, signal }: { input: { text: string }; signal: AbortSignal }) =>
Promise.resolve(input.text)
),
@SandroMaglione
SandroMaglione / copy.tsx
Created May 17, 2025 03:14
State machine for a "copy text" button using `xstate`
import { useActor } from "@xstate/react";
import { setup } from "xstate";
const copyMachine = setup({
types: {
events: {} as { type: "copy"; text: string },
},
}).createMachine({
initial: "Idle",
states: {
@SandroMaglione
SandroMaglione / timer-machine.ts
Created May 13, 2025 10:11
Actor logic for a timer implemented using `xstate` ⏱️
import { assign, fromCallback, setup } from "xstate";
type TickEvent = { type: "tick" };
const timerLogic = fromCallback(({ sendBack }) => {
const timer = setInterval(() => {
sendBack({ type: "tick" } satisfies TickEvent);
}, 1000);
return () => {
import { assign, setup } from "xstate";
type Context = {
chunks: Blob[];
mediaRecorder?: MediaRecorder;
submit: (contents: { file: File }) => void;
};
type Events =
| {
@SandroMaglione
SandroMaglione / machine.json
Created July 4, 2024 12:41
VSCode snippet to scaffold the code for a generic state machine with `xstate`
{
"state machine": {
"prefix": "machine",
"description": "Create scaffold for state machine",
"body": [
"import { setup } from \"xstate\";",
"",
"export const machine = setup({}).createMachine({",
" id: \"$0\",",
" initial: \"Idle\",",
@SandroMaglione
SandroMaglione / i18n-satisfies.ts
Last active June 24, 2024 13:28
i18n (Internationalization and localization) in Typescript using `satisfies` only
type Message = string | ((args: any) => string);
type Translation = { en: Message; it: Message };
export type I18n = Record<string, Translation>;
export const t = {
helloWorld: {
en: "Hello World",
it: "Ciao mondo",
},
@SandroMaglione
SandroMaglione / File.ts
Created May 1, 2024 20:56
File upload validation service created using `effect` only
import { Brand, Context, Data, Effect, Layer } from "effect";
type FileMetadata = Readonly<{ type: string; size: number }>;
export type ValidFile = FileMetadata & Brand.Brand<"ValidFile">;
const ValidFile = Brand.nominal<ValidFile>();
class FileTooLargeError extends Data.TaggedError("FileTooLargeError")<
Readonly<{ size: number }>
> {}
@SandroMaglione
SandroMaglione / machine.ts
Created January 3, 2024 18:39
Setup code for an empty state machine in XState v5
import { setup } from "xstate";
const machine = setup({
types: {
context: {} as {},
events: {} as { readonly type: "event"; readonly params: {} },
},
actions: {},
}).createMachine({
id: "machine",
@SandroMaglione
SandroMaglione / parse_zod.ts
Created November 22, 2023 18:21
Helper functions to gradually migrate from `zod` to `@effect/schema`
import { Data, Either } from "effect";
import type { z } from "zod";
export class ZodParseError<In> extends Data.TaggedError("ZodParseError")<{
error: z.ZodError<In>;
}> {}
export const parseZod =
<ReqOut, ReqIn>(schema: z.Schema<ReqOut, z.ZodTypeDef, ReqIn>) =>
<T>(data: T): Either.Either<ZodParseError<ReqIn>, ReqOut> => {
@SandroMaglione
SandroMaglione / fpdart_io_either_extension.dart
Created November 28, 2022 05:55
Run side effects in a chain of IOEither using fpdart
extension IOExtension<L, R> on IOEither<L, R> {
IOEither<L, R> runSideEffect({
final void Function(L l)? onLeft,
final void Function(R r)? onRight,
}) =>
chainFirst(
(r) => IOEither<L, void>.fromIO(
IO(() => onRight?.call(r)),
),
)