Typescript Snippets
Typed Builder Pattern
The following snippet creates a typed object by progressively adding properties, this can be useful for defining different errors in an application.
CAVEAT: In order for the this
in register()
method to work correctly, the definition cannot use an arrow function.
type ErrorRegistry<T extends string> = Record<T, number> & {
register<K extends string>(error: K, code: number): ErrorRegistry<K | T>
}
function createErrorRegistry<T extends string>(domain: T) {
const errorRegistry = {
register<K extends T>(error: K, code: number) {
return {
...this,
[error]: code
} as ErrorRegistry<T | K>
}
} as ErrorRegistry<T>
return errorRegistry
}
const output = createErrorRegistry('app')
.register('linking', 100)
.register('billing', 200)
.register('surface', 200)
Branded Types
The following snippet defines a utility type Brand<any, string>
which can be used to create an alias of an existing type, which is more strict than the original type.
declare const BrandSymbol: unique symbol
type Brand<T, Description extends string> = T & {
[BrandSymbol]: Description
}
// example usage
type UserId = Brand<number, 'UserId'>
function trackUser(userId: UserId) {
console.log('user:', userId)
}
const userOne = 123 as UserId
const userTwo = 123
trackUser(userOne) // ok
trackUser(userTwo) // error
Define Class via Enum (WIP)
NOTE: This has only been tested on TypeScript 5.4.5 and is still expiramental, see here for example.
This allows us to define an enum which will auto-magically be created into a class definition, and then extended. This is great for a simple ORM with SQLite!
// SPECIAL TYPES
type EnumClass<T> = {
new (...args: any[]): T
}
type Writeable<T> = { -readonly [P in keyof T]: T[P] };
type EnumProps<T> = {
[key in keyof T]: number | string | boolean | Date
}
// THE MAGIC
namespace Class {
export function classFromEnum<E, T>(enumSchema: E): EnumClass<T> {
return class {
constructor(args: EnumProps<E>) {
let hiddenState: EnumProps<E> = Object.assign({}, args)
for (const property in enumSchema) {
console.log(`defining property ${property}`)
Object.defineProperty(this, property, {
enumerable: true,
configurable: true,
writable: true,
get value() {
return hiddenState[property]
},
set value(nextValue) {
hiddenState[property] = nextValue
}
})
}
}
} as {
new (args: EnumProps<E>): T
}
}
}
// EXAMPLE UASGES
enum UserSchema {
userId = 'INTEGER NON NULL',
firstName = 'TEXT NON NULL',
lastName = 'TEXT NON NULL',
}
type SchemaBinding = {
userId: number
firstName: string
lastName: string
}
class User extends Class.classFromEnum<typeof UserSchema, SchemaBinding>(UserSchema) {
setName(fullName: string) {
const [firstName, lastName] = fullName.split(" ")
this.firstName = firstName
this.lastName = lastName
}
}
const myUser = new User({
userId: 123,
firstName: 'Bob',
lastName: 'Smitch',
extra: true
})
myUser.setName("Colin Teahan")
console.log(myUser.firstName) // Colin