-
Notifications
You must be signed in to change notification settings - Fork 169
feat(drivers): add type generics to support strongly typed options of drivers #661
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: main
Are you sure you want to change the base?
Conversation
… getters and setters
…ces to support all methods
|
Thanks for the PR and explanations. The main benefit of unstorage is that it abstracts away the implementation of drivers with a unified (same) interface. Adding per-driver extensions takes that benefit away, and is no better than directly using each driver's underlying client (it might be even more powerful and better typed!) Other than options for creating a driver, their low-level types should not vary. I would like to instead shift towards introducing vendor namespaced options like We could try adding these extensions via a global shared interface in a non breaking change way. |
I understand where you are coming from with not wanting to have divergent options in driver to keep a unified way. Though currently we have the behaiviour that some users are using per-driver extensions and will run different runtime behaiviours when switching driver. They cannot tell that this specifc option is not supported by the new driver as the options are currently typed as Although having an api like `get(key: string, commonOptions?: { ttl }, driverSpecificOptions?: { ... } } might be best to allow for a clear driver specific opt in whilst keeping the common options seperated. (But tbh it's just a different flavor to your suggestion) Atleast in my head we can not really work around a breaking change if we want to type the options. I would like to typed options achived in some way. How would you like to proceed? |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #661 +/- ##
==========================================
+ Coverage 59.99% 62.41% +2.41%
==========================================
Files 42 43 +1
Lines 3657 3887 +230
Branches 590 660 +70
==========================================
+ Hits 2194 2426 +232
+ Misses 1460 1458 -2
Partials 3 3 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
For now, I think we should not touch The best first step would be to contribute to add vendor namespaced optional options to the global TransactionOptions interface (currently it is fully untyped on the global level!) And next, we could allow precise types for the LMK if you like to take over these 😊 |
|
Could you elaborate a bit on what you had in mind with the Picking and Omitting? For me it sounds similar to what I came up with,but using the e.g. supported flags + driver name to later on pick/omit out of the global type. Difference being the source type not coming from the driver itself but from picking out of the global To have type safety in the Storage methods this way we would still need to pass along the driver type into the storage to allow for type inference. An example of your idea would be very helpful! Anyway, I would like to help with that 😄 |
|
Roughly what I have in mind: // [per driver]
export interface XYZOptions {}
export interface XYZDriver {
setOptions: {};
getOptions: {};
}
// [_drivers.ts (auto gen)]
export type BuiltinDrivers = {
xyz: XYZDriver;
};
export type GetOptions = {
xyz?: XYZDriver["getOptions"];
};
export type SetOptions = {
xyz?: XYZDriver["setOptions"];
};
// [types.ts]
interface TransactionOptions {
ttl?: number;
}
interface StorageDefinition {
items: unknown;
mounts: Record<string, { driver: keyof BuiltinDrivers }>; // <-- step 2
}
interface Storage<T> {
getItem: (key: string, opts?: TransactionOptions & GetOptions) => any;
setItem: (
key: string,
value: any,
opts?: TransactionOptions & SetOptions
) => void;
}
|
|
I think I got the idea It's a 2 step process and for now only implement step 1 until the old storage interface is removed . I think I can work something out. I have a bit of an issue with the A: this implies all drivers support it which is wrong. |
We should make it optional type + JSDocs to mention only some drivers support it
Yeah my bad it should be only on set, so not on transactionOptions 😆 |
Implements support for typed options from driver. Resolves #660
So I think I better explain what is going on here.
I added an optional type argument for the drivers to declare their option types (get, set, remove, has, getKeys).
This type argument is passed to the Storage (via the driver) where the actual type is then extracted and passed onto the methods.
It achives strongly typed options in the methods, for example
getfrom the specific driver used.I tried to deduce what kind of options are needed in what method, but please double check them in the
DriverandStoragetypes.As a side note, there is no type safety for the options inside the
createStoragefunction, though as we currently always (as far as I tell) just pass them right back into the driver, there should be no issues.As part of this I had to add these types to the
netlify-blobdriver. There you can see the strongly typed options for theset,getandgetKeysin action.From here we can go into each driver and set their option types to get strong type support in their option methods.
I hope my explanation makes sense.
Please take a look.
If you have any questions, please feel free to ask right away!