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
[Canvas] Add Types to Functions #35087
[Canvas] Add Types to Functions #35087
Conversation
Pinging @elastic/kibana-canvas |
💔 Build Failed |
Not sure I'm understanding correctly, but does this mean things like
|
@lukasolson Nice catch. @w33ble can you explain the relationship between |
💔 Build Failed |
Is there a reason you defined the type as Seems like it would fit better if you did context than arguments, since that's the order of the arguments in |
@w33ble I can change the order, but you'd be forced to add |
@w33ble For example:
would become
|
💔 Build Failed |
aafca71
to
778e592
Compare
💔 Build Failed |
@clintandrewhall I think |
778e592
to
622e56b
Compare
As requested, I've updated this PR to only include the TS changes. I'm still making some changes around naming. |
💔 Build Failed |
💔 Build Failed |
💔 Build Failed |
💔 Build Failed |
/** | ||
* Utility type: gathers values of a collection as a type for use as a type. | ||
*/ | ||
export type ValuesOf<T extends any[]> = T[number]; |
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.
TS ramp-up (for me) question, what's the difference between this and eg. Array<T>
?
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.
You should only use Array<T>
for complex type expressions, (and eslint
will complain if you deviate). For example: string[]
and FooType[]
are preferable to Array<string>
or Array<FooType>
, but Array<{foo: string}>
is preferable in that case.
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.
I read it - correctly? - as:
- "You should use Array for complex type expressions only" (ie. not for simple expressions, though I'm not yet clear on what constitutes simple vs complex)
string[]
andFooType[]
are semantically, but not stylistically equivalent toArray<string>
andArray<FooType>
, resp.
I tried to trigger the syntax check, entering
export type ValuesOf<T extends any[]> = Array<T>;
but it didn't balk, maybe it still accepts it or I don't run the right linter. Also, ValuesOf
and UnionToIntersection
seem to be unused atm. All these are only curiosities, not sure if they're important at all.
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.
I think generics may be an exception...?
*/ | ||
// prettier-ignore | ||
export type AvailableFunctionNames = | ||
AvailableFunctions<typeof commonFunctions[number]>['name'] & |
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.
First of all, incredible work, learning so much just by looking through this! How can AvailableFunctionNames
be used? It's not being referred to now, does it have an impact without use, or if not, what can in theory be hooked up to it?
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.
This is going to be used for i18n, for starters. You'll see it's usefulness in my next diff.
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.
Here's a practical example. In this case, the AvailableFunctions
type can be used to enforce the structure of the FunctionHelpDict
type, throwing a TS error if any of the functions are missing.
/** This type uses the collection of available functions, (which are all
* `FunctionFactory`), to derive the name and argument types from them. This
* allows for validation that 1/ every function available is listed, and 2/ every
* function argument has a help string present.
*/
type FunctionHelp<T> = T extends FunctionFactory<
infer Name,
infer Context,
infer Arguments
>
? {
[key in Name]: {
help: string;
args: { [key in keyof Arguments]: string };
}
}
: never;
/**
* This type represents an exhaustive dictionary of Function help strings,
* organized by Function and then Function Argument.
*
* This type indexes the existing function factories, reverses the union to an
* intersection, and produces the dictionary of strings.
*/
type FunctionHelpDict = UnionToIntersection<FunctionHelp<typeof functions[number]>>;
/**
* Help text for Canvas Functions should be properly localized. This function will
* return a dictionary of help strings, organized by Canvas Function specification
* and then by available arguments.
*/
export const getFunctionHelp = (): FunctionHelpDict => {
return {
alterColumn: {
help: i18n.translate('xpack.canvas.functions.alterColumnHelpText', {
defaultMessage:
'Converts between core types, eg string, number, null, boolean, date and rename columns',
}),
args: {
column: i18n.translate('xpack.canvas.functions.alterColumn.args.columnHelpText', {
defaultMessage: 'The name of the column to alter',
}),
type: i18n.translate('xpack.canvas.functions.alterColumn.args.typeHelpText', {
defaultMessage: 'The type to convert the column to. Leave blank to not change type',
}),
name: i18n.translate('xpack.canvas.functions.alterColumn.args.nameHelpText', {
defaultMessage: 'The resultant column name. Leave blank to not rename',
}),
},
},
💔 Build Failed |
💚 Build Succeeded |
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.
Incredible, tight fitting types PR!
x-pack/plugins/canvas/canvas_plugin_src/functions/common/all.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/canvas/canvas_plugin_src/functions/common/alterColumn.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/canvas/canvas_plugin_src/functions/common/alterColumn.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/canvas/canvas_plugin_src/functions/common/sort.ts
Outdated
Show resolved
Hide resolved
x-pack/plugins/canvas/canvas_plugin_src/functions/common/plot/get_flot_axis_config.ts
Show resolved
Hide resolved
x-pack/plugins/canvas/canvas_plugin_src/functions/common/plot/get_font_spec.ts
Show resolved
Hide resolved
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.
Thanks @clintandrewhall, I learnt a ton from this PR and there's still much to absorb!
💔 Build Failed |
💚 Build Succeeded |
* Reducing changeset to TS-only * Update names; fix a few bugs * Test fixes * Add browser and server functions * Update ts-ignore comments; convert pie; break up TS defs * Convert const to func * Plot conversion * Tweaks to documentation * Fix deleted file * Fix type errors * Update yarn.lock * Address feedback
* Reducing changeset to TS-only * Update names; fix a few bugs * Test fixes * Add browser and server functions * Update ts-ignore comments; convert pie; break up TS defs * Convert const to func * Plot conversion * Tweaks to documentation * Fix deleted file * Fix type errors * Update yarn.lock * Address feedback
💔 Build Failed |
Summary
Depends on #35749(merged).Addresses #40160
This PR isn't easy. This prepares for i18n by adding strong types to Canvas Functions. I'm publishing this as a WIP to gather feedback as I go.
It's taken me several days to get Typescript working with Canvas Functions. But, as a result of that effort, we have a ton of new features to support i18n:
Define and Enforce Function Arguments
Canvas Functions have their arguments defined as individual properties of the
args
property. Each argument has one or more types, regardless of if it's expecting an array or single value of that type, expressed as an array of strings:This difference is now typed, and the type of each argument is available to
fn
:In addition, the presence of the
resolve
property set tofalse
will now enforce that the argument types be functions:Define and Enforce Context
By providing a generic type to represent the context passed into the Function, we can enforce it in
fn
: