Last active
September 25, 2023 13:49
-
-
Save ralphschuler/c0f4a9d7d5a4cdb80d98a9faf65ecc3a to your computer and use it in GitHub Desktop.
Typescript Code Snippets I (found/wrote/generated using ai)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BetterMap<k, v> extends Map<k, v> { | |
update(key:k, updater: (v:v, k:k) => v, notset:v = undefined) { | |
if(this.has(key)) this.set(key, updater(this.get(key), key)) | |
else this.set(key, notset) | |
} | |
filter(predicate: (v:v, k:k) => boolean) { | |
const newMap = new BetterMap<k, v>() | |
const entries = Array.from(this.entries()) | |
for(const [key, value] of entries) { | |
if(predicate(value, key)) newMap.set(key, value) | |
} | |
return newMap | |
} | |
merge(map: Map<k, v>, resolve: (k:k, a:v, b:v) => v = (k, a, b) => b) { | |
const entries = Array.from(map.entries()) | |
for(const [key, value] of entries) { | |
if(this.has(key)) this.set(key, resolve(key, this.get(key), value)) | |
else this.set(key, value) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BetterSet<v> extends Set<v> { | |
filter(predicate: (v: v) => boolean) { | |
const newSet = new BetterSet<v>() | |
const entries = Array.from(this.entries()) | |
for(const [value] of entries) { | |
if (predicate(value)) newSet.add(value) | |
} | |
return newSet | |
} | |
merge(set: Set<v>) { | |
const entries = Array.from(set.entries()) | |
for (const kv of entries) { | |
this.add(kv[0]) | |
} | |
} | |
except(set: Set<v>) { | |
const newSet = new Set<v>() | |
const entries = Array.from(set.entries()) | |
for(const [value] of entries) { | |
if(!this.has(value)) newSet.add(value) | |
} | |
return newSet | |
} | |
both(set: Set<v>) { | |
const newSet = new Set<v>() | |
const entries = Array.from(set.entries()) | |
for(const [value] of entries) { | |
if (this.has(value)) newSet.add(value) | |
} | |
return newSet | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Connection<T> { | |
weight: number; | |
neuron: Neuron<T>; | |
} | |
class Neuron<T> { | |
private incomingConnections: Connection<T>[] = []; | |
private outgoingConnections: Connection<T>[] = []; | |
private bias: number; | |
constructor(bias: number) { | |
this.bias = bias; | |
} | |
connect(neuron: Neuron<T>, weight: number): void { | |
this.outgoingConnections.push({ weight, neuron }); | |
neuron.incomingConnections.push({ weight, neuron: this }); | |
} | |
activate(input: T): T { | |
let sum = 0; | |
for (const connection of this.incomingConnections) { | |
sum += connection.weight * connection.neuron.activate(input); | |
} | |
return (input as any) + sum; // We assume T is a numeric type here, you can adjust as needed. | |
} | |
propagate(error: T): void { | |
for (const connection of this.outgoingConnections) { | |
connection.neuron.propagate(error as any); // Adjust as needed based on T. | |
} | |
} | |
toObject(): object { | |
return { | |
bias: this.bias, | |
incomingConnections: this.incomingConnections.map(connection => ({ | |
weight: connection.weight, | |
neuron: connection.neuron.toObject() | |
})), | |
outgoingConnections: this.outgoingConnections.map(connection => ({ | |
weight: connection.weight, | |
neuron: connection.neuron.toObject() | |
})) | |
}; | |
} | |
} | |
class Layer<T> { | |
private neurons: Neuron<T>[] = []; | |
constructor(length: number, createNeuron: (bias: number) => Neuron<T>) { | |
for (let i = 0; i < length; i++) { | |
this.neurons.push(createNeuron(Math.random())); | |
} | |
} | |
connect(layer: Layer<T>): void { | |
for (const neuronA of this.neurons) { | |
for (const neuronB of layer.neurons) { | |
neuronA.connect(neuronB, Math.random()); | |
} | |
} | |
} | |
toObject(): object { | |
return { | |
neurons: this.neurons.map(neuron => neuron.toObject()) | |
}; | |
} | |
} | |
class Network<T> { | |
private inputLayer: Layer<T>; | |
private hiddenLayers: Layer<T>[] = []; | |
private outputLayer: Layer<T>; | |
constructor( | |
inputLayerLength: number, | |
hiddenLayerLengths: number[], | |
outputLayerLength: number, | |
createNeuron: (bias: number) => Neuron<T> | |
) { | |
this.inputLayer = new Layer(inputLayerLength, createNeuron); | |
for (const length of hiddenLayerLengths) { | |
this.hiddenLayers.push(new Layer(length, createNeuron)); | |
} | |
this.outputLayer = new Layer(outputLayerLength, createNeuron); | |
} | |
connect(): void { | |
this.inputLayer.connect(this.hiddenLayers[0]); | |
for (let i = 0; i < this.hiddenLayers.length - 1; i++) { | |
this.hiddenLayers[i].connect(this.hiddenLayers[i + 1]); | |
} | |
this.hiddenLayers[this.hiddenLayers.length - 1].connect(this.outputLayer); | |
} | |
activate(input: T[]): T[] { | |
const output = this.inputLayer.neurons.map( | |
(neuron: Neuron<T>, index: number) => neuron.activate(input[index]) | |
); | |
return this.outputLayer.neurons.map( | |
(neuron: Neuron<T>, index: number) => neuron.activate(output[index]) | |
); | |
} | |
propagate(error: T[]): void { | |
const output = this.inputLayer.neurons.map( | |
(neuron: Neuron<T>, index: number) => neuron.activate(error[index]) | |
); | |
this.outputLayer.neurons.map( | |
(neuron: Neuron<T>, index: number) => neuron.propagate(error[index]) | |
); | |
} | |
train(input: T[], output: T[]): void { | |
const outputActivation = this.activate(input); | |
const error = output.map((value, index) => value - outputActivation[index]); | |
this.propagate(error); | |
} | |
toObject(): object { | |
return { | |
inputLayer: this.inputLayer.toObject(), | |
hiddenLayers: this.hiddenLayers.map(layer => layer.toObject()), | |
outputLayer: this.outputLayer.toObject(), | |
}; | |
} | |
} | |
export { | |
Neuron, | |
Layer, | |
Network, | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type Rule = { | |
symbol: SymbolType; | |
transform: Array<SymbolType>; | |
probability: number; | |
} | |
export enum SymbolType { | |
North = "N", | |
East = "E", | |
South = "S", | |
West = "W", | |
Forward = "F", | |
Checkpoint = "C", | |
Jump = "J" | |
} | |
export class LSystem { | |
private axiom: string; | |
private rules: Array<Rule>; | |
constructor(axiom: string, rules: Rule[]) { | |
this.axiom = axiom; | |
this.rules = rules; | |
} | |
public generate(iterations: number): string { | |
let result = this.axiom; | |
for (let i = 0; i < iterations; i++) { | |
result = this.applyRules(result); | |
} | |
return result; | |
} | |
private applyRules(str: string): string { | |
let result = ""; | |
for (let i = 0; i < str.length; i++) { | |
const rules = this.rules.filter(r => r.symbol === str[i]); | |
if (rules.length > 0) { | |
const rule = this.getRandomRule(rules); | |
result += rule.transform; | |
} else { | |
result += str[i]; | |
} | |
} | |
return result; | |
} | |
private getRandomRule(rules: Rule[]): Rule { | |
const random = Math.random(); | |
let sum = 0; | |
for (let i = 0; i < rules.length; i++) { | |
sum += rules[i].probability; | |
if (random < sum) { | |
return rules[i]; | |
} | |
} | |
return rules[rules.length - 1]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Types for property and method mappings. | |
*/ | |
type PropertyTypeMap = Record<string, Record<string, string>>; | |
type MethodTypeMap = Record<string, Record<string, Function>>; | |
const configProperties: PropertyTypeMap = {}; | |
const interfaceMethods: MethodTypeMap = {}; | |
/** | |
* Decorator to collect properties with their types. | |
* @param {string} type - The expected type of the property. | |
*/ | |
export function ConfigProperty(type: string, defaultValue?: any) { | |
return (target: object, propertyKey: string) => { | |
addToMap(configProperties, target.constructor.name, propertyKey, type); | |
if (defaultValue !== undefined) { | |
target[propertyKey] = defaultValue; | |
} | |
}; | |
} | |
/** | |
* Decorator to collect methods. | |
* @param {object} target - The target object. | |
* @param {string} propertyKey - The key of the property. | |
* @param {PropertyDescriptor} descriptor - The property descriptor. | |
*/ | |
export function InterfaceMethod(target: object, propertyKey: string, descriptor: PropertyDescriptor) { | |
addToMap(interfaceMethods, target.constructor.name, propertyKey, descriptor.value); | |
} | |
/** | |
* Utility function to add an entry to a map. | |
* @param {Record<string, any>} map - The map to which to add the entry. | |
* @param {string} className - The name of the class. | |
* @param {string} key - The key to add. | |
* @param {any} value - The value to associate with the key. | |
*/ | |
function addToMap(map: Record<string, any>, className: string, key: string, value: any) { | |
map[className] = map[className] || {}; | |
map[className][key] = value; | |
} | |
/** | |
* Function to validate and freeze the unified config object. | |
* @param {UnifiedConfig<any>} config - The config object to validate. | |
* @param {Function[]} mixins - The array of mixin classes. | |
*/ | |
function validateAndFreezeConfig(config: UnifiedConfig<any>, mixins: Function[]) { | |
Object.freeze(config); | |
mixins.forEach((Mixin) => { | |
const className = Mixin.name; | |
const expectedConfig = configProperties[className] || {}; | |
const actualConfigKeys = Object.keys(expectedConfig); | |
actualConfigKeys.forEach((key) => { | |
if (config[key] === undefined) { | |
throw new Error(`Missing config property: ${key} in ${className}`); | |
} | |
const expectedType = expectedConfig[key]; | |
const actualType = typeof config[key]; | |
if (expectedType !== actualType) { | |
throw new Error(`Type mismatch for ${key} in ${className}: expected ${expectedType}, got ${actualType}`); | |
} | |
}); | |
}); | |
} | |
type ExtractConfig<T> = T extends new (config: infer Config) => any ? Config : never; | |
type UnifiedConfig<T extends any[]> = { | |
[K in keyof T]: ExtractConfig<T[K]>; | |
}[number]; | |
/** | |
* Function to create a new class with mixin functionality. | |
* @param {...Function} mixins - The mixin classes to include. | |
* @returns {Promise<new (config: UnifiedConfig<T>) => any>} - The newly created class. | |
*/ | |
export async function createClass<T extends Array<new (config: any) => any>>( | |
...mixins: T | |
): Promise<new (config: UnifiedConfig<T>) => any> { | |
// Perform any asynchronous operations here, if needed | |
return class { | |
constructor(config: UnifiedConfig<T>) { | |
validateAndFreezeConfig(config, mixins); | |
for (const Mixin of mixins) { | |
const mixinInstance = new Mixin(config); | |
Object.assign(this, mixinInstance); | |
} | |
} | |
}; | |
} | |
// Example usage | |
interface ILoggingMixin { | |
logLevel: 'info' | 'warn' | 'error'; | |
log(message: string): void; | |
} | |
class LoggingMixinInstance implements ILoggingMixin { | |
@ConfigProperty('string', 'info') | |
logLevel: 'info' | 'warn' | 'error'; | |
@InterfaceMethod | |
log(message: string): void { | |
console.log(`[${this.logLevel}] ${message}`); | |
} | |
} | |
interface ICachingMixin { | |
cacheSize: number; | |
setCache(key: string, value: any): void; | |
} | |
class CachingMixinInstance implements ICachingMixin { | |
@ConfigProperty('number', 100) | |
cacheSize: number; | |
@InterfaceMethod | |
setCache(key: string, value: any): void { | |
// Implement caching logic here | |
} | |
} | |
// Usage | |
(async () => { | |
const MyClass = await createClass(LoggingMixinInstance, CachingMixinInstance); | |
const myInstance = new MyClass({ | |
logLevel: 'info', | |
cacheSize: 100 | |
}); | |
myInstance.log('Hello, world!'); | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export type ComparatorFunction<T> = (a: T, b: T) => number; | |
export type PriorityQueueOptions<T> = { | |
comparatorFunction: ComparatorFunction<T>; | |
initialValues?: Array<T>; | |
} | |
export type Optional<T> = T | null; | |
export class PriorityQueue<T> { | |
private values: Array<T|null> = [] | |
private comparatorFunction: ComparatorFunction<T>; | |
private length: number = 0; | |
public constructor(options: PriorityQueueOptions<T>) { | |
this.comparatorFunction = options.comparatorFunction; | |
if (options.initialValues) { | |
options.initialValues.forEach(value => this.enqueue(value)) | |
} | |
} | |
public enqueue(value: T): void { | |
if (this.values.length <= this.length) { | |
this.values.length = Math.max(1, this.values.length * 2) | |
} | |
this.values[this.length++] = value | |
this.bubbleUp(); | |
} | |
public dequeue(): Optional<T|null> { | |
if (this.length === 0) { | |
return null | |
} | |
const node = this.values[0] | |
if (this.length === 1) { | |
this.length = 0 | |
this.values[0] = null | |
return node | |
} | |
this.values[0] = this.values[this.length - 1] | |
this.values[this.length - 1] = null | |
this.length-- | |
this.bubbleDown() | |
return node | |
} | |
public heapSort(): Array<T|null> { | |
return Array.from({length: this.length}, () => this.dequeue()); | |
} | |
private parent(nodeIndex: number): number|null { | |
if (nodeIndex === 0) { | |
return null | |
} | |
return (nodeIndex - 1) >>> 1 | |
} | |
private leftChild(nodeIndex: number): number|null { | |
const child = (nodeIndex * 2) + 1 | |
if (child >= this.length ){ | |
return null | |
} | |
return child | |
} | |
private rightChild(nodeIndex: number): number|null { | |
const child = (nodeIndex * 2) + 2 | |
if (child >= this.length) { | |
return null | |
} | |
return child | |
} | |
private bubbleUp(nodeIndex: number = this.length - 1) { | |
const parent = this.parent(nodeIndex) | |
if (parent !== null && this.comparatorFunction(this.values[nodeIndex] as T, this.values[parent] as T) < 0) { | |
const node = this.values[nodeIndex] | |
this.values[nodeIndex] = this.values[parent] | |
this.values[parent] = node | |
this.bubbleUp(parent) | |
} | |
return | |
} | |
public bubbleDown(nodeIndex: number = 0) { | |
const leftChild = this.leftChild(nodeIndex) | |
const rightChild = this.rightChild(nodeIndex) | |
let swapCandidate = nodeIndex | |
if (leftChild !== null && this.comparatorFunction(this.values[swapCandidate] as T, this.values[leftChild] as T) > 0) { | |
swapCandidate = leftChild | |
} | |
if (rightChild !== null && this.comparatorFunction(this.values[swapCandidate] as T, this.values[rightChild] as T) > 0) { | |
swapCandidate = rightChild | |
} | |
if (swapCandidate !== nodeIndex) { | |
const node = this.values[nodeIndex] | |
this.values[nodeIndex] = this.values[swapCandidate] | |
this.values[swapCandidate] = node | |
this.bubbleDown(swapCandidate) | |
} | |
return | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class SafeArray<T> { | |
private array: Array<T>; | |
private addQueue: Array<T>]; | |
private removeQueue: Array<T>; | |
public constructor(items?: Array<T> ) { | |
this.array = items || []; | |
this.addQueue = []; | |
this.removeQueue = []; | |
} | |
public get isEmpty(): boolean { | |
return this.array.length + this.addQueue.length === 0; | |
} | |
public get length(): number { | |
return this.array.length + this.addQueue.length - this.removeQueue.length; | |
} | |
public add(item: T): void { | |
this.addQueue.push(item); | |
} | |
public remove(item: T): void { | |
this.removeQueue.push(item); | |
} | |
public filter(predicate: (item: T) => boolean): Array<T> { | |
const result: Array<T> = []; | |
this.forEach((item: T) => { | |
if (predicate(item)) { | |
result.push(item); | |
} | |
}); | |
return result; | |
} | |
public forEach(callback: (item: T) => void): void { | |
this.addQueued(); | |
this.removeQueued(); | |
for (const item of this.array) { | |
if (this.removeQueue.indexOf(item) === -1) { | |
callback(item); | |
} | |
} | |
this.removeQueued(); | |
} | |
private addQueued(): void { | |
this.array = this.array.concat(this.addQueue); | |
} | |
private removeQueued(): void { | |
this.array = this.array.filter((item: T) => !this.removeQueue.includes(item)) | |
this.removeQueue = []; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment