Last active
November 10, 2022 19:07
-
-
Save filmaj/839e9124e2752b0a636a01a43e58ab35 to your computer and use it in GitHub Desktop.
Revisions
-
Filip Maj revised this gist
Nov 10, 2022 . 1 changed file with 94 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,94 @@ // Some user-defined parameters based on primitive types type BaseParamDefinition<N, T> = { type: N; default: T }; type BooleanParamDefinition = BaseParamDefinition<"boolean", boolean>; type StringParamDefinition = BaseParamDefinition<"string", string>; type NumberParamDefinition = BaseParamDefinition<"number",number>; // A more complex parameter type: an object, with inputs, and an array that specifies which of the inputs are required. type ObjectParamDefinition< Inputs extends ParameterSetDefinition<PrimitiveParameterDefinition>, RequiredInputs extends RequiredProperties<Inputs>, > = { type: "object"; input_parameters: InputDefinition<Inputs, RequiredInputs>; }; type PrimitiveParameterDefinition = | BooleanParamDefinition | StringParamDefinition | NumberParamDefinition; type ParameterDefinition = PrimitiveParameterDefinition | ObjectParamDefinition<ParameterSetDefinition<PrimitiveParameterDefinition>, RequiredProperties<ParameterSetDefinition<PrimitiveParameterDefinition>>>; // Used to define inputs at both function level and function object parameter sub-level type ParameterSetDefinition< ParamDefn extends ParameterDefinition, > = { [key: string]: ParamDefn }; // Used in conjunction with ParameterSetDefinition: returns an array of string literals derived from the keys of the parameter set. type RequiredProperties<PropSet extends ParameterSetDefinition<ParameterDefinition>> = (keyof PropSet)[]; type InputDefinition< Properties extends ParameterSetDefinition<ParameterDefinition>, Required extends RequiredProperties<Properties>, > = { required: Required; properties: Properties; }; type FunctionDefinitionArgs< Inputs extends ParameterSetDefinition<ParameterDefinition>, RequiredInputs extends RequiredProperties<Inputs>, > = { title: string; input_parameters: InputDefinition<Inputs, RequiredInputs>; }; const DefineFunction = < Inputs extends ParameterSetDefinition<ParameterDefinition>, RequiredInputs extends RequiredProperties<Inputs>, >( definition: FunctionDefinitionArgs<Inputs, RequiredInputs>, ) => { return new FunctionDefinition(definition); }; class FunctionDefinition< Inputs extends ParameterSetDefinition<ParameterDefinition>, RequiredInputs extends RequiredProperties<Inputs>, > { constructor( public definition: FunctionDefinitionArgs< Inputs, RequiredInputs >, ) { this.definition = definition; } } const myfunc = DefineFunction({ title: "hihi", input_parameters: { properties: { "a_string": { type: "string", default: "STRING!", }, "an_optional_string": { type: "string", default: "...string", }, "an_object": { type: "object", input_parameters: { properties: { "object_string": { type: "string", default: "[string]" }, "optional_object_string": { type: "string", default: "string?" }, }, required: ["object_string", "whatever"] // <-- does not work! I expect TS to complain about 'whatever' } }, }, required: ["a_string", "an_object"] // works, both elements reference existing keys of the top-level `properties` // required: ["a_string", "an_object", "hi"] // also works! "hi" is not listed under `properties` so TS complains, as expected }, }); -
Filip Maj revised this gist
Nov 10, 2022 . 1 changed file with 21 additions and 25 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -21,8 +21,10 @@ type ParameterDefinition = PrimitiveParameterDefinition | ObjectParamDefinition; type ParameterSetDefinition< ParamDefn extends ParameterDefinition = ParameterDefinition, > = { [key: string]: ParamDefn }; // NOTE: RequiredProperties AKA PossibleParameterKeys type RequiredProperties<PropSet extends ParameterSetDefinition> = (keyof PropSet)[]; // NOTE: InputDefinition AKA ParameterPropertiesDefinition type InputDefinition< Properties extends ParameterSetDefinition, Required extends RequiredProperties<Properties>, @@ -91,45 +93,39 @@ type FunctionInputRuntimeType< Param extends ParameterDefinition, CurrentDepth extends RecursionDepthLevel = 0, > = CurrentDepth extends MaxRecursionDepth ? "debug:maxrecursiondepth" // TODO: Custom Type parameter support // : Param extends CustomTypeParameterDefinition ? FunctionInputRuntimeType< //Param["type"]["definition"], //IncreaseDepth<CurrentDepth> //> : Param["type"] extends "string" ? string : Param["type"] extends "number" ? number : Param["type"] extends "boolean" ? boolean // TODO: Array Type parameter support // : Param["type"] extends typeof SchemaTypes.array //? Param extends TypedArrayParameterDefinition //? TypedArrayFunctionInputRuntimeType<Param> //: any[] : Param["type"] extends "object" ? Param extends ObjectParamDefinition ? TypedObjectFunctionInputRuntimeType<Param> : "debug:object-type-that-does-not-extend-ObjectParamDefinition" : "debug:ded"; type TypedObjectFunctionInputRuntimeType<Param extends ObjectParamDefinition> = Param["required"] extends string[]// TODO: checking if Param[required] extends from RequiredProperties<Param["properties"]> doesn't seem to work here? ? RuntimeParameters<Param["properties"], Param["required"]> : { "debug:poo": boolean }; type RuntimeParameters< Props extends ParameterSetDefinition, Req extends RequiredProperties<Props>, > = // TODO (h/t mkantor): the below commented out line doesn't work since we have to 'index' into the specific type for the particular input. It could be a StringParam, BoolParam, or more complex types like ObjectParam, etc. //Record<Req[number], FunctionInputRuntimeType<??wat?? Props[what?]>> & Partial<Props>; & { [k in Req[number]]: FunctionInputRuntimeType< // TODO: <-- this "k in Req" iterator seems to work fine for a Function's input_parameters.properties - but not for an object input's properties. Props[k] >; } @@ -138,8 +134,6 @@ type RuntimeParameters< Props[k] >; }; const myfunc = DefineFunction({ title: "hihi", @@ -166,10 +160,12 @@ const myfunc = DefineFunction({ }, }); const _handler: FunctionHandler<typeof myfunc.definition> = (context) => { context.inputs; context.inputs.a_string; // this should be string context.inputs.an_optional_string; // this should be string | undefined context.inputs.an_object; context.inputs.an_object?.object_string; // this should be string - but it's not! it is string | undefined context.inputs.an_object?.optional_object_string; // this should be string | undefined return {}; }; -
Filip Maj revised this gist
Nov 10, 2022 . 1 changed file with 17 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -1,12 +1,12 @@ // Some user-defined parameters based on primitive types type BaseParamDefinition<N, T> = { type: N; default: T }; type BooleanParamDefinition = BaseParamDefinition<"boolean", boolean>; type StringParamDefinition = BaseParamDefinition<"string", string>; type NumberParamDefinition = BaseParamDefinition<"number",number>; type AllPrimitiveValues = string | number | boolean; type ObjectValue = Record<string, AllPrimitiveValues>; type ObjectParamDefinition = & Omit<BaseParamDefinition<"object", ObjectValue>, "default"> & InputDefinition< ParameterSetDefinition<PrimitiveParameterDefinition>, RequiredProperties<ParameterSetDefinition<PrimitiveParameterDefinition>> @@ -17,7 +17,7 @@ type PrimitiveParameterDefinition = | NumberParamDefinition; type ParameterDefinition = PrimitiveParameterDefinition | ObjectParamDefinition; // maybe useful change: make ParameterSetDefinition take a generic, so that it can be reused for both function input properties and object type input properties type ParameterSetDefinition< ParamDefn extends ParameterDefinition = ParameterDefinition, > = { [key: string]: ParamDefn }; @@ -61,6 +61,7 @@ class FunctionDefinition< } } // Is FunctionParameters needed? Most of the time it is constrained further to RuntimeParameters<I, RI> type FunctionParameters = Record<string, any> | undefined; type FunctionContext<In extends FunctionParameters> = { inputs: In; @@ -152,14 +153,23 @@ const myfunc = DefineFunction({ type: "string", default: "...string", }, "an_object": { type: "object", properties: { "object_string": { type: "string", default: "[string]" }, "optional_object_string": { type: "string", default: "string?" }, }, required: ["object_string"] }, }, required: ["a_string"] }, }); const handler: FunctionHandler<typeof myfunc.definition> = (context) => { context.inputs; context.inputs.a_string; context.inputs.an_optional_string; context.inputs.an_object; return {}; }; -
Filip Maj created this gist
Nov 9, 2022 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,165 @@ // Some user-defined parameters based on primitive types type BaseParamDefinition<T> = { type: string; default: T }; type BooleanParamDefinition = BaseParamDefinition<boolean>; type StringParamDefinition = BaseParamDefinition<string>; type NumberParamDefinition = BaseParamDefinition<number>; type AllPrimitiveValues = string | number | boolean; type ObjectValue = Record<string, AllPrimitiveValues>; type ObjectParamDefinition = & BaseParamDefinition<ObjectValue> & InputDefinition< ParameterSetDefinition<PrimitiveParameterDefinition>, RequiredProperties<ParameterSetDefinition<PrimitiveParameterDefinition>> >; type PrimitiveParameterDefinition = | BooleanParamDefinition | StringParamDefinition | NumberParamDefinition; type ParameterDefinition = PrimitiveParameterDefinition | ObjectParamDefinition; // maybe useful change: make the following take a generic, to differentiate between function inputs and object type input properties type ParameterSetDefinition< ParamDefn extends ParameterDefinition = ParameterDefinition, > = { [key: string]: ParamDefn }; type RequiredProperties<PropSet extends ParameterSetDefinition> = (keyof PropSet)[]; type InputDefinition< Properties extends ParameterSetDefinition, Required extends RequiredProperties<Properties>, > = { required: Required; properties: Properties; }; type FunctionDefinitionArgs< Inputs extends ParameterSetDefinition, RequiredInputs extends RequiredProperties<Inputs>, > = { title: string; input_parameters: InputDefinition<Inputs, RequiredInputs>; }; const DefineFunction = < Inputs extends ParameterSetDefinition, RequiredInputs extends RequiredProperties<Inputs>, >( definition: FunctionDefinitionArgs<Inputs, RequiredInputs>, ) => { return new FunctionDefinition(definition); }; class FunctionDefinition< Inputs extends ParameterSetDefinition, RequiredInputs extends RequiredProperties<Inputs>, > { constructor( public definition: FunctionDefinitionArgs< Inputs, RequiredInputs >, ) { this.definition = definition; } } type FunctionParameters = Record<string, any> | undefined; type FunctionContext<In extends FunctionParameters> = { inputs: In; }; type BaseHandler< In extends FunctionParameters, Context extends FunctionContext<In>, > = { ( context: Context, ): FunctionParameters; }; type FunctionHandler<Definition> = Definition extends FunctionDefinitionArgs<infer I, infer RI> ? BaseHandler< RuntimeParameters<I, RI>, FunctionContext<RuntimeParameters<I, RI>> > : never; /** @description Defines accepted depth values */ type RecursionDepthLevel = 0 | 1 | 2 | 3 | 4 | 5; /** @description Defines the max depth we want to recurse */ type MaxRecursionDepth = 5; type FunctionInputRuntimeType< Param extends ParameterDefinition, CurrentDepth extends RecursionDepthLevel = 0, > = // Recurse through Custom Types, stop when we hit our max depth CurrentDepth extends MaxRecursionDepth ? "maxrecursiondepth" //: Param extends CustomTypeParameterDefinition ? FunctionInputRuntimeType< //Param["type"]["definition"], //IncreaseDepth<CurrentDepth> //> // Not a Custom Type, so assign the runtime value : Param["type"] extends "string" ? string : Param["type"] extends "number" ? number : Param["type"] extends "boolean" ? boolean //: Param["type"] extends typeof SchemaTypes.array //? Param extends TypedArrayParameterDefinition //? TypedArrayFunctionInputRuntimeType<Param> //: any[] : Param["type"] extends "object" ? Param extends ObjectParamDefinition ? TypedObjectFunctionInputRuntimeType<Param> : "object-type-that-does-not-extend-ObjectParamDefinition" //: Param["type"] extends //| typeof SlackSchemaTypes.user_id //| typeof SlackSchemaTypes.usergroup_id //| typeof SlackSchemaTypes.channel_id //| typeof SlackSchemaTypes.date //| typeof SlackSchemaTypes.message_ts ? string //: Param["type"] extends typeof SlackSchemaTypes.timestamp ? number //: Param["type"] extends typeof SlackSchemaTypes.rich_text //? any : "ded"; type TypedObjectFunctionInputRuntimeType<Param extends ObjectParamDefinition> = Param["required"] extends RequiredProperties<Param["properties"]> ? { rainbows: boolean } : { poo: boolean }; type RuntimeParameters< Props extends ParameterSetDefinition, Req extends RequiredProperties<Props>, > = & { [k in Req[number]]: FunctionInputRuntimeType< Props[k] >; } & { [k in keyof Props]?: FunctionInputRuntimeType< Props[k] >; }; // TODO: the below doesn't work since we have to 'index' into the specific type for the particular input. It could be a StringParam, BoolParam, etc. //Record<Req[number], FunctionInputRuntimeType<??wat?? Props[what?]>> & Partial<Props>; const myfunc = DefineFunction({ title: "hihi", input_parameters: { properties: { "a_string": { type: "string", default: "STRING!", }, "an_optional_string": { type: "string", default: "...string", }, }, required: ["a_string"], }, }); const handler: FunctionHandler<typeof myfunc.definition> = (context) => { context.inputs; context.inputs.a_string; context.inputs.an_optional_string; return {}; };