Skip to content

Instantly share code, notes, and snippets.

@jamiebuilds
jamiebuilds / tradeoffs-in-value-derived-types-in-typescript.md
Last active December 16, 2022 17:21
Value-derived types in TypeScript are super powerful, but you should be thoughtful in how/when you use them

Tradeoffs in value-derived types in TypeScript

Many of the more "advanced" typescript features can be used for creating "value-derived" types.

At its simplest form:

let vehicle = { name: "Van", wheels: 4 }

Bump all npm outdated dependencies

npm install $(npm outdated --json | jq -r 'to_entries | map("\(.key)@^\(.value.latest)") | join(" ")')
npm run typecheck

assert() (sometimes called invariant())

Instead of checks like:

if (value === null) {
  throw new Error("missing value")
}
doSomethingThatNeedsValue(value)
#!/usr/bin/env node
const fs = require("fs/promises")
const globby = require("globby")
const makeDir = require("make-dir")
const path = require("path")
const svgo = require("svgo")
const REPO_ROOT = path.join(__dirname, "..")
async function main() {
<picture size-hint="100% 550px">
<source src="/images/hero~640x550@1x.jpg" width="640" height="550" resolution="1x"/>
<source src="/images/hero~640x550@2x.jpg" width="1280" height="1100" resolution="2x"/>
<source src="/images/hero~768x550@1x.jpg" width="768" height="550" resolution="1x"/>
<source src="/images/hero~768x550@2x.jpg" width="1536" height="1100" resolution="2x"/>
<source src="/images/hero~1024x550@1x.jpg" width="1024" height="550" resolution="1x"/>
<source src="/images/hero~1024x550@2x.jpg" width="2048" height="1100" resolution="2x"/>
<source src="/images/hero~1280x550@1x.jpg" width="1280" height="550" resolution="1x"/>
<source src="/images/hero~1280x550@2x.jpg" width="2560" height="1100" resolution="2x"/>
<source src="/images/hero~1536x550@1x.jpg" width="1536" height="550" resolution="1x"/>

Remix Conventions Proposals

I'm splitting these off into separate changes that could be made to Remix that I think would make it more flexible and provide more value.

.route. naming

Remix (any many other tools right now) contains what I'll call "magic exports":

function t(){let t=new Set;return{listen:e=>(t.add(e),()=>{t.delete(e)}),emit(){t.forEach((t=>t()))}}}function e(){return Math.random().toString(36).substring(2,8)}function n(t,e,n){return Math.min(Math.max(t,e),n)}function r(t,e){return(t.startsWith(e)?"":e)+t}function a({pathname:t,search:e,hash:n}){return{pathname:r(t,"/"),search:r(e,"?"),hash:r(n,"#")}}function s({pathname:t,search:e,hash:n}){return t+("?"===e?"":e)+("#"===n?"":n)}function h(t){return s(a(t))}function u(t){let[e,n=""]=t.split("#"),[r,s=""]=e.split("?");return a({pathname:r,search:s,hash:n})}function i(t){return s(u(t.substring(1)))}function o(t){if("string"==typeof t)return t;{let{pathname:e="",search:n="",hash:r=""}=t;return h({pathname:e,search:n,hash:r})}}function l(t){return{location(){return e=t.path(),n=t.state(),r=t.key(),{...u(e),state:n,key:r};var e,n,r},push(e,n){let r=o(e);t.push(r,n)},replace(e,n){let r=o(e);t.push(r,n)},go(e){t.go(e)},back(){t.go(-1)},forward(){t.go(1)},listen:e=>t.listen(e)}}function p(n){let r=n.history,a=t
function capitalize(locale, string) {
let segmenter = new Intl.Segmenter(locale, { granularity: "grapheme" })
let result = ""
for (let item of segmenter.segment(string)) {
if (item.index === 0) {
result += item.segment.toLocaleUpperCase(locale)
} else {
result += item.segment
}
// if (!window.L) { window.L = function () { console.log(arguments);} } // optional EZ quick logging for debugging
/**
* A modified (improved?) version of the jQuery plugin design pattern
* See http://docs.jquery.com/Plugins/Authoring (near the bottom) for details.
*
* ADVANTAGES OF EITHER FRAMEWORK:
* - Encapsulates additional plugin action methods without polluting the jQuery.fn namespace
* - Ensures ability to use '$' even in compat modes
*