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
Type definitions: QueryBuilder is no longer a Promise #3515
Comments
Your original typing was wrong. You are returning Correct typing would be:
If you want to return a
Or you can resolve
|
@elhigu Thank you so much for you quick response.
In Typescript, Promise is an interface. Interface implementation in Typescript can be achieved in two ways: explicitly and implicitly. Typescript, as an OOP language supports polymorphism. Keeping this in mind, knex 0.19.5 implemented implicitly Promise, but this implementation is no longer supported in knex 0.20.1, ¿is this made on purpose?
Thats true, but it's an unnecesary limit. Digging in the type definitions it seems you really wanted to implement the Promise interface: interface ChainableInterface<T = any> extends Pick<Promise<T>, "then" | "catch" | "finally">
... ¿is there any reason for not implementing it? I've been doing some tests to verify that QueryBuilder implements the Promise interface (https://repl.it/@RobertoPintos/knex-test), unfortunatelly it's true that the getter implementation of the Symbol.toStringTag is missing (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag) ¿Do you consider interesting implementing this getter? QueryBuilder.toString is already implemented so it should be easy and this would allow to consider a QueryBuilder as a Promise
That approach would be correct, but this change has a cost at runtime and there is no need to do that. |
@lorefnon can decide about this, but in my opinion it is dangerous to thing that you are saying that object returned from method is a Promise, when the returned object is actually not a Promise and does not behave like one. Though you are right that one can think about it from many sides, but I don't see any upside of making QueryBuilder to pretend being a promise - only confusion.
Typescript is pretty much all about adding unnecessary limits on top of javascript 😅 First adding types and then not breaking that added typesafety does not sound like an unnecessary limitation.
We really would have wanted to implement
Actually there is no extra cost, because you need to convert it to promise in either way at some point to execute that query. Cost is only moved to earlier and query execution starts right away when method is called. It is also necessary if you want to get Promise returned instead of thenable. Otherwise you are better off returning I'm sure you know the difference what happens when you return a promise or thenable, but I'll add this example of expected behaviour anyways just to be extra clear:
Anyways this was my view and I leave this to typescript maintainers to decide what to do 👍 |
Is |
@elhigu now I understand your point of view. You are absolutely right. Sorry, this was a bit confusing. Sincerely, I knew that theenables do not need to conform the Promises/A+ spec, but I did not get it in this comment 😅. Now everything is clear, I will reconsider my code. But maybe docs should be changed, some parts of them seem to be a bit confusing. |
@elhigu I will keep the issue opened until the Typescript maintainers answer about the type question (on my opinion, PromiseLike is a good choice), but pls feel free to close this as soon as you want. |
I agree with @elhigu that returning query builder from something whose return type is Promise is confusing esp. for someone new. I am not opposed to adding a Depending on
I don't quite see what is confusing in there. This seems well described to me:
|
That part describes well the behavior of the queries, but what I miss is what @elhigu explained previously: successive calls to QueryBuilder.then will generate different query executions. I don't find that in the docs. Maybe I'm missing something. |
I think we can close the issue now. Thank you so much for the quick responses and knowledge :) |
I agree... it is not correct, since "coerces" means that it will modify QueryBuilder to behave like a promise, which it does not. Originally QueryBuilder was meant to be implemented to work like that, but I'm glad it never was implemented correctly. There would have been internal promise which is resolved just once and its result would have been returned on every I think that documentation should be fixed to say that every call to then |
Environment
Knex version: 0.20.1
Database + version: N/A.
OS: N/A.
This is a Typescript definition issue related, so I'm tagging @lorefnon.
Bug
Typescript is unable to threat a QueryBuilder as a Promise. On knex 0.19.5 it was possible to create a query like this one:
But now it's no longer possible:
Conversion of type 'QueryBuilder<unknown, number>' to type 'Promise<any>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Property '[Symbol.toStringTag]' is missing in type 'QueryBuilder<unknown, number>' but required in type 'Promise<any>'.
In order to fix this I have to use this ugly workaround:
Is this a bug or it's the expected behavior?
The text was updated successfully, but these errors were encountered: