more type safe dual signature, closes #2967
Type
- [ ] Refactor
- [x] Feature
- [ ] Bug Fix
- [ ] Optimization
- [ ] Documentation Update
Description
Ad discussed in #2967, the dual type signature could be improved to avoid inferring an (...args: any[]) => any function type, which is assignable to every function signature you define for your dual api, and instead be precise over the implementation signature used. Of course the rest of the type signature would still be unsafe, but that's unavoidable.
This should help prevent errors when the type signature of the implementation used for the dual api is different to the one used as the final signature of such dual api.
NOTICE:
There are a couple of tests failing, regarding the schema package, which should not be related to this change. In fact, if you run the tests on the main this pr is based on, those tests keep failing.
This PR should be type level only. I added dtslint tests for the dual signature type checks I did in the first place that brought this change to exist. This should help to assert those cases are preserved in the future.
Related
- Closes #2967
🦋 Changeset detected
Latest commit: cbce4588eddb0c2d12de88bdc81413756da201eb
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 30 packages
| Name | Type |
|---|---|
| @effect/typeclass | Major |
| @effect/platform | Major |
| effect | Minor |
| @effect/schema | Major |
| @effect/printer-ansi | Major |
| @effect/printer | Major |
| @effect/cli | Major |
| @effect/cluster-browser | Major |
| @effect/cluster-node | Major |
| @effect/cluster | Major |
| @effect/experimental | Major |
| @effect/platform-browser | Major |
| @effect/platform-bun | Major |
| @effect/platform-node-shared | Major |
| @effect/platform-node | Major |
| @effect/rpc-http | Major |
| @effect/rpc | Major |
| @effect/sql-d1 | Major |
| @effect/sql-mssql | Major |
| @effect/sql-mysql2 | Major |
| @effect/sql-pg | Major |
| @effect/sql-sqlite-bun | Major |
| @effect/sql-sqlite-node | Major |
| @effect/sql | Major |
| @effect/cluster-workflow | Major |
| @effect/opentelemetry | Major |
| @effect/sql-drizzle | Major |
| @effect/sql-sqlite-react-native | Major |
| @effect/sql-sqlite-wasm | Major |
| @effect/vitest | Major |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
Imho seems to be over complexifying usage, also it would be a breaking change that potentially breaks user code, not sure about it
Imho seems to be over complexifying usage, also it would be a breaking change that potentially breaks user code, not sure about it
Usage should be the same in the "common case" scenario. There are a couple of instances where it can't infer automatically the whole type you'd like your dual signature to be, and require you to type the Other and Impl parts of it as generic types. This, btw, remove the need to type the implementation internally though, so it's more like moving and typing more directly than just inferring.
It's true some user code could be breaking due to this change, at least at the type level, since this PR is all about types, even if it's just about reordering types so to put generics in place. But it should help spot places where inference would put you in a possibly bad situation runtime wise, due to (...args: any[]) => any being inferred, which if you want to, could be considered a "fixed bug", in the sense the original user code could be potentially broken already, and this pr help spotting and let user fix those cases.
This would be a major change, the changeset will need adjusting.
dual was also made quite "relaxed" on purpose, so I'm on fence about this change.
This would be a major change, the changeset will need adjusting.
dualwas also made quite "relaxed" on purpose, so I'm on fence about this change.
Just to have a clear view on this so that everyone is aligned, the "new" signature would be as relaxed as the old one. You can always tell ts your dual signature is something else other than the actual implementation, which is always the case, no matter how strict you write the dual signature. This only enforces the implementation you write don't end up being treated as an "any" function early on without you noticing.