Skip to content

Instantly share code, notes, and snippets.

View jmakeig's full-sized avatar

Justin Makeig jmakeig

View GitHub Profile
@jmakeig
jmakeig / validation.ts
Last active August 12, 2026 06:06
Yet another attempt to simplify entity validation in TypeScript
// https://www.typescriptlang.org/play/?declaration=false&target=9&ts=5.9.3#code/PTAEFUBcEsBtpgUwM4ChIE8AOjQDkBXWWAQwCNZEAeAFQD5QBeUG0AH1ADsjYBuVVCFABRTjCRpMOEWIQYqeEgFtciAB6REnACbJQySACdonAOYNmAb1QBIQ4hLaA9p1gZQAbQAKoE-mWIALoAXPpGJqb8AL6gAGSg1jakZIiwoQbGZvw2nAHp4VmoUfxSuABKiABmCgGg6po6ehkRFjLi8ooqdPzo2LgAwgQGTiqGTG1yVADkAMZDkCOIhlMM8Yn2ptAuoYTE5JTTeE6GkAAWylPsoFPCALLCAIKXHFMAUg9eD-3P1wAyJJALt1bMhEKYVGIdjx9tQpgBlVKIGaQH43MRLLDGUGo-rHLDHAGIVFw24AIRW0R6pVAAHVjgBrWBORzjUTtaYAdwZTMcKziCVsc2Go1CFWqs3mi2WwJsyGgAC9EKFuEoUmMONxiJSBEIAGokeDaAFbTi9aReAGncYVRwuNwPQyGEjyLyGJw4E4YADSiAwwNQJk0hkqJBmuAAkshkARcOsHM5XO4VFGSKYlWFMpFbPZbYnQFhLQB+UIWs7ZHMJtygGZObSIYsZiLRATU-WGwnaKgAeQIkAstg4llAFbt7iNgNCPcgvGH8dHoAAbgboOOTQ3OIgF0tQFEBwlZ7mq+OSKECJx6ZwnBzODOR3ml+2YNtQG2V8aXN3ewxigIZqQoy+y6rh+U4MIkwAAFQQbYoAQSwKCQHoHKnIgZzbiQs7RrAkC+HoJgPiuAB0oBeiY2igE4lSgByiDQIY5FnACviQIAmAR6GhXBgsaW4ADQwXBZC9qAShOAYoBDKmuAcnAsCgCkoALKA5w6JQoAYQABq+46INo6lsb4nAEeRBiEoR-HACCgIwDMuEAPr4UBAAU9hYZAp7npe14AJShC5RA4dAehDneVZGe+nChFp4VUGeF5Xpw34CjYdioQQh
@jmakeig
jmakeig / entities.ts
Last active January 23, 2026 21:17
Updated version of Pending<Entity>.
// types/entities.d.ts
// ============================================================================
// Types (least concrete to most)
// ============================================================================
// Branded ID type using unique symbol
declare const ID_BRAND: unique symbol;
export type ID = string & { readonly [ID_BRAND]: true };

Given a type Thing create a type Pending<Thing> with the following behavior:

  • Root-level properties of type ID are nullable
  • Properites that are entities, i.e. that have top-level ID property, are replaced with { id_prop: ID; }, where id_prop is name name of the entity’s ID property.
  • Same for Arrays of entities with ID properties, i.e. Array<{something: ID; …}> is mapped to Array<Ref<Entity>>
  • Primitives are loosened to allow the original type along with string or null, for example for easy instantiation from FormData
@jmakeig
jmakeig / README.md
Last active November 15, 2025 19:40

Validation

  • Strongly typed unknownEntity
  • Accumulation of all validation issues, not just the first (or the last)
  • Return the prepared entity, not just Boolean validation result. For example, parsing a string input as a number.
@jmakeig
jmakeig / entities.d.ts
Last active October 6, 2025 01:45
Pipeline entity model
declare const IDBrand: unique symbol;
type ID = string & { [IDBrand]: void };
/**
* Allows for each property’s original type or string.
* This is useful for accepting values from HTML forms,
* which only allow string inputs.
*/
type Stringish<T> = {
[p in keyof T]: T[p] | string;
@jmakeig
jmakeig / customer-revenue.sql
Last active November 22, 2025 20:04
Use case: Timeseries data that’s stored densely, but needs to be reported sparsely, i.e. with explicit zeros for missing periods. (RIGHT JOIN for the win!)
-- PostgreSQL syntax
DROP TABLE IF EXISTS revenue;
CREATE TABLE revenue (
month TEXT,
customer INT,
channel TEXT,
list NUMERIC
);
@jmakeig
jmakeig / example.js
Last active January 6, 2023 06:30
JSDoc can’t describe some generic functions declared in Typescript
/** @typedef {{name: string; title: string; description: string; sets: any[]; }} Workout */
/** @typedef {{name: string; instructions: string;}} Exercise */
/** @typedef {"en" | "fr" | "de" | "jp" | "zh" | "he"} Lang */
/** @typedef {string | {[L in Lang]?: string}} Message */
/** @typedef {{for: string, message?: Message}} ValidationResult */
/**
* @template Entity
* @typedef {{(condition: {(entity: Entity): boolean}, id: string, message: Message): {(entity: Entity): ValidationResult[]}}} RuleCreator<Entity>
@jmakeig
jmakeig / timer.css
Created December 29, 2021 20:56
Timer CSS animation
svg {
display: inline-block;
height: 90px;
width: 90px;
}
svg.timer {
transform: rotate(-90deg);
overflow: visible;
}
circle.gague {
@jmakeig
jmakeig / fy-date-converter.xlsx
Created July 2, 2020 22:54
Calendar date to MarkLogic fiscal year conversion
="FY"&IF(MONTH(G2)=1, YEAR(G2), YEAR(G2)+1) & "Q"&IF(MONTH(G2)=1, 4, FLOOR((MONTH(G2)+1)/3,1))