Last active
April 26, 2024 11:15
-
-
Save GhomKrosmonaute/00da4eb3e8ac48a751602288fcf71835 to your computer and use it in GitHub Desktop.
[TypeScript] Transfer of argument typings from a class property to a class callback with a transformation from immutable Array type to immutable Object type.
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
/// CORE /// | |
/** | |
* Extracts the name of an input | |
*/ | |
type InputName<T> = T extends Input<infer Name, any> ? Name : never | |
/** | |
* Extracts the type of an input | |
*/ | |
type InputType<T> = T extends Input<any, infer Type> ? Types[Type] : never | |
/** | |
* Extracts the outputs of an array of inputs | |
*/ | |
type Outputs<Inputs extends readonly Input<any, TypeName>[]> = { | |
[K in InputName<Inputs[number]>]: InputType< | |
Extract<Inputs[number], { name: K }> | |
> | |
} | |
/** | |
* Represent the type name of an input | |
*/ | |
type TypeName = keyof Types | |
/// SETTINGS /// | |
/** | |
* Example types | |
*/ | |
interface Types { | |
boolean: boolean | |
number: number | |
string: string | |
} | |
/// EXAMPLES /// | |
/** | |
* Example input | |
*/ | |
interface Input<Name extends string, Type extends TypeName> { | |
readonly name: Name | |
readonly type: Type | |
} | |
/** | |
* Example class | |
*/ | |
class Example<const Inputs extends readonly Input<any, TypeName>[]> { | |
constructor( | |
public inputs: Inputs, | |
public run: (outputs: Outputs<Inputs>) => void | |
) {} | |
compute(raw: string) { | |
const outputs: Outputs<Inputs> = {} as any | |
const rawInputs = raw.split(/\s+/) | |
for (const input of this.inputs) { | |
const rawInput = rawInputs.shift() | |
if (!rawInput) throw new Error(`Missing input ${input.name}`) | |
// @ts-expect-error | |
outputs[input.name] = this.convert(rawInput, input.type) | |
} | |
this.run(outputs) | |
} | |
convert<T extends keyof Types>(raw: string, type: T): Types[T] { | |
return ( | |
type === "string" ? raw : type === "number" ? Number(raw) : Boolean(raw) | |
) as Types[T] | |
} | |
} | |
/// TESTS /// | |
const example = new Example( | |
[ | |
{ name: "name", type: "string" }, | |
{ name: "age", type: "number" }, | |
{ name: "isMajor", type: "boolean" }, | |
], | |
(outputs) => { | |
outputs.name // => string (John) | |
outputs.age // => number (42) | |
outputs.isMajor // => boolean (true) | |
} | |
) | |
example.compute("John 42 true") // => OK | |
example.compute("John 42") // => Error: Missing input isMajor |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This can be used in your discord.js bots to transfer argument types to run params, resolved by argument names and types.