-
Notifications
You must be signed in to change notification settings - Fork 149
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
Finish TypeScript Migration #512
Conversation
@JustinBeckwith / Node team: This PR fails CI with the following errors (re
Note that |
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.
Sorry for the slight delay. I looked over the individual PRs and left a few minor comments. I think mostly this looks good but we need to fix the merge conflicts and revert the breaking changes (sorry).
throw new Error(`${ | ||
invalidArgumentMessage( | ||
arg, 'precondition')} Input contains more than one condition.`); | ||
} |
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.
Should this be checking for invalid preconditions? E.g. if I typo and do {exist: true}
instead of {exists: true}
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 filed b/125363185 to tackle this at a later point.
dev/src/write-batch.ts
Outdated
* @private | ||
* @param arg The argument name or argument index (for varargs methods). | ||
* @param value The object to validate. | ||
* @param options Optional validation options specifying whether the valued can |
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.
"valued" => "value" here and elsewhere.
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.
Fixed
dev/src/validate.ts
Outdated
* | ||
* @private | ||
*/ | ||
function formatPlural(num, str) { | ||
return `${num} ${str}` + (num === 1 ? '' : 's'); | ||
export interface AllowOptional { |
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.
nit: I don't love AllowOptional
and AllowRange
as names. Normally I like to name classes / interfaces as nouns. I think maybe OptionalOption
and RangeOptions
would be better, though admittedly OptionalOption
is a bit awkward. :)
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.
Renamed to RequiredArgumentOptions
and NumericRangeOptions
. Not sure if better but it is different!
dev/src/write-batch.ts
Outdated
* @param allowExist Whether to allow the 'exists' preconditions. | ||
*/ | ||
function validatePrecondition( | ||
arg: string|number, value: unknown, allowExist: boolean): void { |
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.
allowExist => allowExists ? (you use "/allowExists=/" elsewhere)
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.
Done
dev/src/write-batch.ts
Outdated
if (conditions > 1) { | ||
throw new Error(`${ | ||
invalidArgumentMessage( | ||
arg, 'precondition')} Input contains more than one condition.`); |
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 error and above use "condition" instead of "precondition". Is that intentional? We should probably use whatever leads to the most consistency across our APIs / docs / errors.
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 was, and the argument for that is that a precondition can only contain one condition. I can also see that someone might treat { exists: true }
and { lastUpdateTime: Date.now() }
as single preconditions, in which case { exists: true, lastUpdateTime: Date.now() }
would make two preconditions. I don't have a strong preference here, but since I managed to confuse you, let's err on the side of less confusion and use the term precondition
.
dev/src/write-batch.ts
Outdated
* @param value The object to validate. | ||
* @param options Optional validation options specifying whether the valued can | ||
* be omitted. | ||
* @returns 'true' if the input is a valid SetOptions object. |
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.
Should be @throws ...
. I think several other methods are wrong too.
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.
Fixed, but I only found this one instance. There are still some internal helpers that do return a boolean.
dev/test/document.ts
Outdated
@@ -957,29 +958,29 @@ describe('set document', () => { | |||
firestore.doc('collectionId/documentId').set({foo: 'bar'}, 'foo'); | |||
}) | |||
.to.throw( | |||
'Argument "options" is not a valid SetOptions. Input is not an object.'); | |||
'Argument "options" is not a valid set() option. Input is not an object.'); |
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 reads a bit weird. Maybe "is not a valid set() options object." ? though admittedly that's a bit verbose.
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.
Changed to "is not a valid set() options argument".
@@ -349,7 +348,7 @@ export class DocumentSnapshot { | |||
* console.log(`Retrieved data: ${JSON.stringify(data)}`); | |||
* }); | |||
*/ | |||
data(): DocumentData|undefined { | |||
data(): {[field: string]: any}|undefined { // tslint:disable-line no-any |
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.
Are all of these remaining instances of "any" expected to stay forever? Or do you intend further cleanup passes? In my ideal world we'd either remove them or comment them. :-) This one may be intentional so that our users don't have to do instanceof checks on the data they get back? I'm not sure though.
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.
Yes, I think that we do need to use any
here. We don't have a way to control what we are giving back, and by using any
as a return type we indicate that the user has to do some type checking of their own. I added a comment.
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.
by using
any
as a return type we indicate that the user has to do some type checking of their own
Sorry for the nit, but that's not actually what any
does. 😀 any
makes it so you don't have to do any type checking (you can do anything you want with it and TypeScript won't complain). If we want to force the user to do type-checking, then we should return unknown
(new in TS 3.x) instead, which you can't do anything with unless you first do type-checking on it.
That said, using any here is consistent with the mobile SDK (https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore-types/index.d.ts#L24), so I'm fine with 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.
Uhm, that's what I meant (kind of, but not really).
Changed to
// We deliberately use `any` in the external API to not impose type-checking
// on end users.
|
||
return true; | ||
export function validateQueryOrder(arg: string|number, op: unknown): void { | ||
validateEnumValue(arg, op, Object.keys(directionOperators), {optional: true}); |
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.
Per discussions with Gil, etc. during the push to GA, I think we want to unroll the breaking change we made here (and elsewhere). And in fact we may want to relax the mobile SDK to match.
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 brought back the old behavior by pre-preprocessing op
.
@@ -60,7 +58,6 @@ const comparisonOperators: | |||
{[k: string]: api.StructuredQuery.FieldFilter.Operator} = { | |||
'<': 'LESS_THAN', | |||
'<=': 'LESS_THAN_OR_EQUAL', | |||
'=': 'EQUAL', | |||
'==': 'EQUAL', |
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.
Per discussions with Gil, etc. during the push to GA, I think we want to continue to allow '=' to avoid the breaking change.
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 changed the validation function to accept both =
and ==
. The function returns the sanitized value.
Codecov Report
@@ Coverage Diff @@
## master #512 +/- ##
==========================================
- Coverage 95.93% 95.85% -0.09%
==========================================
Files 24 24
Lines 1943 1928 -15
Branches 161 166 +5
==========================================
- Hits 1864 1848 -16
Misses 57 57
- Partials 22 23 +1
Continue to review full report at Codecov.
|
Codecov Report
@@ Coverage Diff @@
## master #512 +/- ##
==========================================
- Coverage 95.93% 95.85% -0.08%
==========================================
Files 24 24
Lines 1943 1932 -11
Branches 161 168 +7
==========================================
- Hits 1864 1852 -12
Misses 57 57
- Partials 22 23 +1
Continue to review full report at Codecov.
|
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.
LGTM with nits.
@@ -349,7 +348,7 @@ export class DocumentSnapshot { | |||
* console.log(`Retrieved data: ${JSON.stringify(data)}`); | |||
* }); | |||
*/ | |||
data(): DocumentData|undefined { | |||
data(): {[field: string]: any}|undefined { // tslint:disable-line no-any |
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.
by using
any
as a return type we indicate that the user has to do some type checking of their own
Sorry for the nit, but that's not actually what any
does. 😀 any
makes it so you don't have to do any type checking (you can do anything you want with it and TypeScript won't complain). If we want to force the user to do type-checking, then we should return unknown
(new in TS 3.x) instead, which you can't do anything with unless you first do type-checking on it.
That said, using any here is consistent with the mobile SDK (https://github.com/firebase/firebase-js-sdk/blob/master/packages/firestore-types/index.d.ts#L24), so I'm fine with this.
dev/src/reference.ts
Outdated
@@ -785,6 +786,8 @@ export class QuerySnapshot { | |||
* }); | |||
* }); | |||
*/ | |||
// We deliberately use `any` to allow users to use arbitrary objects as the | |||
// callback's context. |
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 you can use unknown
here since we don't care what the type is, we just pass it through.
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.
Yes, that works. Not sure how .call()
is defined, but the linter doesn't complain.
@@ -165,7 +169,7 @@ export function validateBoolean( | |||
*/ | |||
export function validateNumber( | |||
arg: string|number, value: unknown, | |||
options?: AllowOptional&AllowRange): void { | |||
options?: RequiredArgumentOptions&NumericRangeOptions): void { |
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.
Is this really how clang-format formats this? Yuck. 😒
dev/test/util/helpers.ts
Outdated
@@ -14,20 +14,22 @@ | |||
* limitations under the License. | |||
*/ | |||
|
|||
const v1beta1 = require('../../src/v1beta1'); |
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.
unused?
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.
Removed. Bye bye v1beta1
This PR finishes the Typescript migration of the Firestore Server SDK. As part of this:
unknown
instead ofany
for the user-facing types (only internally, not in the types we shipped)is
to be able to use TypeScript's typechecking.This is the PR that I am planning on merging, and it's also the PR that I am would like to address all feedback in (to reduce merge conflicts). Since it is not very easy to review, I split this out into a series of PRs that are more tightly scoped:
Cleanup: Argument count validation #495 Cleanup: Argument count validation(approved)Cleanup: Validate primitive types #496 Cleanup: Validate primitive types(approved)Cleanup: Move parseGetAllArguments #497 Cleanup: Move parseGetAllArguments(approved)Cleanup: Remove(approved)is
#503 Cleanup: Removeis
refactor: Add strict types for the transaction test #504 Cleanup: Add strict types for the transaction test(approved)Cleanup: Field value validation #505 Cleanup: Field value validation(approved)Cleanup: Misc #506 Cleanup: Misc(approved)Cleanup: Error messages for custom objects #507 Cleanup: Error messages for custom objects(approved)The individual PRs are not meant to compile/pass tests. There should not be anything in this larger PR that is not listed above.
This is fairly low priority, so please take your time to review.
Fixes: b/117464450 and b/119350730