-
Notifications
You must be signed in to change notification settings - Fork 5.5k
feat(sdk): improve configurable_prop types
#16698
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,8 +54,11 @@ type BaseConfigurableProp = { | |
| withLabel?: boolean; | ||
| }; | ||
|
|
||
| // XXX fix duplicating mapping to value type here and with PropValue | ||
| type Defaultable<T> = { default?: T; options?: T[]; }; | ||
| type Defaultable<T> = { default?: T; options?: T[] }; | ||
|
|
||
| // Define a type for string-based property options | ||
| export type StringPropOptionObject = { label?: string; value: string }; | ||
| export type StringPropOption = string | StringPropOptionObject; | ||
|
|
||
| export type ConfigurablePropAlert = BaseConfigurableProp & { | ||
| type: "alert"; | ||
|
|
@@ -69,7 +72,9 @@ export type ConfigurablePropApp = BaseConfigurableProp & { | |
| type: "app"; | ||
| app: string; | ||
| }; | ||
| export type ConfigurablePropBoolean = BaseConfigurableProp & { type: "boolean"; }; | ||
| export type ConfigurablePropBoolean = BaseConfigurableProp & { | ||
| type: "boolean"; | ||
| } & Defaultable<boolean>; | ||
| export type ConfigurablePropInteger = BaseConfigurableProp & { | ||
| type: "integer"; | ||
| min?: number; | ||
|
|
@@ -81,54 +86,128 @@ export type ConfigurablePropObject = BaseConfigurableProp & { | |
| export type ConfigurablePropString = BaseConfigurableProp & { | ||
| type: "string"; | ||
| secret?: boolean; | ||
| } & Defaultable<string>; | ||
| default?: string; | ||
| options?: StringPropOption[]; | ||
| }; | ||
| export type ConfigurablePropStringArray = BaseConfigurableProp & { | ||
| type: "string[]"; | ||
| secret?: boolean; // TODO is this supported | ||
| } & Defaultable<string[]>; // TODO | ||
| // | { type: "$.interface.http" } // source only | ||
| // | { type: "$.interface.timer" } // source only | ||
| // | { type: "$.service.db" } | ||
| // | { type: "data_store" } | ||
| // | { type: "http_request" } | ||
| // | { type: "sql" } -- not in component api docs! | ||
| default?: string[]; | ||
| options?: StringPropOption[]; | ||
| }; | ||
| export type ConfigurablePropNumber = BaseConfigurableProp & { | ||
| type: "number"; | ||
| min?: number; | ||
| max?: number; | ||
| } & Defaultable<number>; | ||
| export type ConfigurablePropNumberArray = BaseConfigurableProp & { | ||
| type: "number[]"; | ||
| } & Defaultable<number>; | ||
| export type ConfigurablePropIntegerArray = BaseConfigurableProp & { | ||
| type: "integer[]"; | ||
| } & Defaultable<number>; | ||
| export type ConfigurablePropBooleanArray = BaseConfigurableProp & { | ||
| type: "boolean[]"; | ||
| } & Defaultable<boolean>; | ||
| export type ConfigurablePropDiscordChannel = BaseConfigurableProp & { | ||
| type: "$.discord.channel"; | ||
| [key: string]: unknown; | ||
| } & Defaultable<string>; | ||
| export type ConfigurablePropDiscordChannelArray = BaseConfigurableProp & { | ||
| type: "$.discord.channel[]"; | ||
| [key: string]: unknown; | ||
| } & Defaultable<string>; | ||
|
||
|
|
||
| export type ConfigurablePropInterfaceHttp = BaseConfigurableProp & { | ||
| type: "$.interface.http"; | ||
| [key: string]: unknown; | ||
| }; | ||
| export type ConfigurablePropInterfaceTimer = BaseConfigurableProp & { | ||
| type: "$.interface.timer"; | ||
| [key: string]: unknown; | ||
| }; | ||
| export type ConfigurablePropServiceDb = BaseConfigurableProp & { | ||
| type: "$.service.db"; | ||
| [key: string]: unknown; | ||
| }; | ||
| export type ConfigurablePropDataStore = BaseConfigurableProp & { | ||
| type: "datastore"; | ||
| [key: string]: unknown; | ||
| }; | ||
| export type ConfigurablePropHttpRequest = BaseConfigurableProp & { | ||
| type: "http_request"; | ||
| [key: string]: unknown; | ||
| }; | ||
| export type ConfigurablePropSql = BaseConfigurableProp & { type: "sql" }; | ||
|
|
||
| export type ConfigurableProp = | ||
| | ConfigurablePropAlert | ||
| | ConfigurablePropAny | ||
| | ConfigurablePropApp | ||
| | ConfigurablePropBoolean | ||
| | ConfigurablePropBooleanArray | ||
| | ConfigurablePropInteger | ||
| | ConfigurablePropIntegerArray | ||
| | ConfigurablePropNumber | ||
| | ConfigurablePropNumberArray | ||
| | ConfigurablePropObject | ||
| | ConfigurablePropString | ||
| | ConfigurablePropStringArray | ||
| | (BaseConfigurableProp & { type: "$.discord.channel"; }); | ||
| | ConfigurablePropDiscordChannel | ||
| | ConfigurablePropDiscordChannelArray | ||
| | ConfigurablePropInterfaceHttp | ||
| | ConfigurablePropInterfaceTimer | ||
| | ConfigurablePropServiceDb | ||
| | ConfigurablePropDataStore | ||
| | ConfigurablePropHttpRequest | ||
| | ConfigurablePropSql; | ||
|
|
||
| export type ConfigurableProps = Readonly<ConfigurableProp[]>; | ||
|
|
||
| export type PropValue<T extends ConfigurableProp["type"]> = T extends "alert" | ||
| ? never | ||
| : T extends "any" | ||
| ? any // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| : T extends "app" | ||
| ? { authProvisionId: string; } | ||
| : T extends "boolean" | ||
| ? boolean | ||
| : T extends "integer" | ||
| ? number | ||
| : T extends "object" | ||
| ? object | ||
| : T extends "string" | ||
| ? string | ||
| : T extends "string[]" | ||
| ? string[] // XXX support arrays differently? | ||
| : never; | ||
| ? any // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| : T extends "app" | ||
| ? { authProvisionId: string } | ||
| : T extends "boolean" | ||
| ? boolean | ||
| : T extends "boolean[]" | ||
| ? boolean[] | ||
| : T extends "integer" | ||
| ? number | ||
| : T extends "integer[]" | ||
| ? number[] | ||
| : T extends "object" | ||
| ? object | ||
| : T extends "string" | ||
| ? string | ||
| : T extends "string[]" | ||
| ? string[] | ||
| : T extends "number" | ||
| ? number | ||
| : T extends "number[]" | ||
| ? number[] | ||
| : T extends "$.discord.channel" | ||
| ? string | ||
| : T extends "$.discord.channel[]" | ||
| ? string[] | ||
| : T extends | ||
| | "$.interface.http" | ||
| | "$.interface.timer" | ||
| | "$.service.db" | ||
| | "datastore" | ||
| | "http_request" | ||
| | "sql" | ||
| ? unknown | ||
| : never; | ||
|
|
||
| export type ConfiguredProps<T extends ConfigurableProps> = { | ||
| [K in T[number] as K["name"]]?: PropValue<K["type"]> | ||
| [K in T[number] as K["name"]]?: PropValue<K["type"]>; | ||
| }; | ||
|
|
||
| // as returned by API (configurable_props_json from `afterSave`) | ||
| export type V1Component<T extends ConfigurableProps = any> = { // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| export type V1Component<T extends ConfigurableProps = ConfigurableProps> = { | ||
| name: string; | ||
| key: string; | ||
| version: string; | ||
|
|
@@ -137,7 +216,9 @@ export type V1Component<T extends ConfigurableProps = any> = { // eslint-disable | |
| component_type?: string; | ||
| }; | ||
|
|
||
| export type V1DeployedComponent<T extends ConfigurableProps = any> = { // eslint-disable-line @typescript-eslint/no-explicit-any | ||
| export type V1DeployedComponent< | ||
| T extends ConfigurableProps = ConfigurableProps, | ||
| > = { | ||
| id: string; | ||
| owner_id: string; | ||
| component_id: string; | ||
|
|
@@ -171,4 +252,4 @@ export type V1EmittedEvent = { | |
| * The event's unique ID. | ||
| */ | ||
| id: string; | ||
| } | ||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Defaultable is too restrictive for “array-of-X” property kinds
Defaultable<T>hard-codesoptions?: T[].When you reuse it for array property kinds (
"number[]","integer[]","boolean[]", etc.) you end up with:Consequently
defaultandPropValue<"number[]">become incompatible and the compiler will not prevent the error because the mismatch sits in different structural types (prop definition vs. configured value).Consider introducing a dedicated helper for array props or inlining
default/options:Same adjustment is required for
ConfigurablePropIntegerArray,ConfigurablePropBooleanArray, andConfigurablePropDiscordChannelArray.Failing to do so will allow mis-typed defaults to slip into published schema and break user tooling at runtime.
📝 Committable suggestion
🤖 Prompt for AI Agents