-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Typescript Typed events #3085
Typescript Typed events #3085
Conversation
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 for contributing! I think this approach makes sense. What do you think, @goto-bus-stop?
This should be good to go 👍 |
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 looks very promising and definitely a stricter approach to event types. I have one question, other than that I think we are good to go.
|
||
export type DashboardFileEditStartCallback<TMeta> = (file: UppyFile<TMeta>) => void; | ||
export type DashboardFileEditCompleteCallback<TMeta> = (file: UppyFile<TMeta>) => void; | ||
declare module '@uppy/core' { |
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.
Why do we need to declare this module?
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.
It's so the various definitions of the UppyEventMap
interface are additive with the initial @uppy/core
version, and not treated as if they're from separate modules. Typescript refers to this pattern as module augmentation.
Would you be so kind to describe the breaking type change in a comment in #3100 so we can add it later? |
|
||
once<TMeta extends IndexedObject<any> = Record<string, unknown>>(event: 'complete', callback: UploadCompleteCallback<TMeta>): this | ||
on<K extends keyof UppyEventMap, TMeta extends IndexedObject<any>>(event: K, callback: UppyEventMap<TMeta>[K]): this |
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.
Will this not be a breaking change if we flip the order? So TMeta
and then UppyEventMap
?
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 did consider that, however Typescript does not have partial generic interference (yet), so as soon as you specify one generic the rest must be explicitly specified.
Thank you @Hawxy! |
* 'main' of https://github.com/transloadit/uppy: Changelog for 1.31.0 and patches Strictly type uppy events (#3085) Create `onUnmount` in `UIPlugin` for plugins that require clean up (#3093) Companion improve logging (#3103) Fix `editFile` locale usage (#3108)
* main: (23 commits) Release Set node version in `workflows/cdn.yml` to 16.x Release build: add stylelint (#3124) Core: rename allowMultipleUploads to allowMultipleUploadBatches (#3115) meta: enforce `no-unused-vars` linter rule (#3118) writing-plugins: update example to use `i18nInit` (#3122) @uppy/core: reject empty string as valid value for required meta fields (#3119) Safely escape <script> injected code in companion `send-token.js` (#3101) @uppy/dashboard: fix metafield form validation (#3113) Clean up `BACKLOG.md` & add Vimeo as todo Add referrer to transloadit.com link (#3116) @uppy/locales latest version is 1.22.0 🙈 Stricter linter (#3095) @uppy/aws-s3: refactor to use private fields (#3094) build: fix legacy bundle (#3112) Fix locales — point to CDN v1.31.0 Fix typo in `docs/companion.md` Changelog for 1.31.0 and patches Strictly type uppy events (#3085) ...
|
||
off(event: Event, callback: (...args: any[]) => void): this | ||
off<K extends keyof UppyEventMap>(event: K, callback: UppyEventMap[K]): this |
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.
Can we add a version of off
that is similar to on
, like the following?
off<K extends keyof UppyEventMap, TMeta extends IndexedObject<any>>(event: K, callback: UppyEventMap<TMeta>[K]): this
Without that, I can‘t pass the same event handler function to on
and off
:
interface MyMetadata {
...
}
const handleUpload = (file: UploadedUppyFile<MyMetadata, unknown>) => { ... };
// this is fine
uppy.on<'upload-success', MyMetadata>('upload-success', handleUpload);
// however, this leads to the TypeScript error below
uppy.off<'upload-success'>('upload-success', handleUpload);
leads to
error TS2345: Argument of type '(file: UploadedUppyFile<Metadata, unknown>) => void' is not assignable to parameter of type 'UploadSuccessCallback<Record<string, unknown>>'.
Types of parameters 'file' and 'file' are incompatible.
Type 'UploadedUppyFile<Record<string, unknown>, unknown>' is not assignable to type 'UploadedUppyFile<Metadata, unknown>'.
Property 'fileId' is missing in type 'Record<string, unknown>' but required in type 'Metadata'.
103 uppy.off<'upload-success'>('upload-success', handleUpload);
If you want, I can also create a ticket for this
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 for raising this, I'll put up a PR for this shortly.
Closes #2922
Utilizing declaration/interface merging, all events can be typed across all packages.
I'm opening this as a draft to collect feedback before I spend time finishing this off.Positives:
@uppy
package the user installs.Negatives: