Skip to content

Compile time asserts #2367

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

Merged
merged 5 commits into from
Dec 2, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/firestore/src/api/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1429,7 +1429,7 @@ export class QueryDocumentSnapshot extends DocumentSnapshot
typeof data === 'object',
'Document in a QueryDocumentSnapshot should exist'
);
return data as firestore.DocumentData;
return data;
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/api/user_data_converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ export class UserDataConverter {
context.fieldTransforms.length === 0,
'Field transforms should have been disallowed.'
);
return parsed!;
return parsed;
}

/** Sends data through this.preConverter, handling any thrown errors. */
Expand Down
15 changes: 7 additions & 8 deletions packages/firestore/src/core/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,13 +523,12 @@ export class FieldFilter extends Filter {
value instanceof ArrayValue,
'Comparing on key with IN, but filter value not an ArrayValue'
);
assert(
(value as ArrayValue).internalValue.every(elem => {
assert(value.internalValue.every(elem => {
return elem instanceof RefValue;
}),
'Comparing on key with IN, but an array value was not a RefValue'
);
return new KeyFieldInFilter(field, value as ArrayValue);
return new KeyFieldInFilter(field, value);
} else {
assert(
value instanceof RefValue,
Expand All @@ -539,7 +538,7 @@ export class FieldFilter extends Filter {
op !== Operator.ARRAY_CONTAINS && op !== Operator.ARRAY_CONTAINS_ANY,
`'${op.toString()}' queries don't make sense on document keys.`
);
return new KeyFieldFilter(field, op, value as RefValue);
return new KeyFieldFilter(field, op, value);
}
} else if (value.isEqual(NullValue.INSTANCE)) {
if (op !== Operator.EQUAL) {
Expand All @@ -564,13 +563,13 @@ export class FieldFilter extends Filter {
value instanceof ArrayValue,
'IN filter has invalid value: ' + value.toString()
);
return new InFilter(field, value as ArrayValue);
return new InFilter(field, value);
} else if (op === Operator.ARRAY_CONTAINS_ANY) {
assert(
value instanceof ArrayValue,
'ARRAY_CONTAINS_ANY filter has invalid value: ' + value.toString()
);
return new ArrayContainsAnyFilter(field, value as ArrayValue);
return new ArrayContainsAnyFilter(field, value);
} else {
return new FieldFilter(field, op, value);
}
Expand Down Expand Up @@ -765,7 +764,7 @@ export class Bound {
'Bound has a non-key value where the key path is being used.'
);
comparison = DocumentKey.comparator(
(component as RefValue).key,
component.key,
doc.key
);
} else {
Expand All @@ -774,7 +773,7 @@ export class Bound {
docValue !== null,
'Field should exist since document matched the orderBy already.'
);
comparison = component.compareTo(docValue!);
comparison = component.compareTo(docValue);
}
if (orderByComponent.dir === Direction.DESCENDING) {
comparison = comparison * -1;
Expand Down
10 changes: 5 additions & 5 deletions packages/firestore/src/core/sync_engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,7 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
assert(!!queryView, `No query view found for ${query}`);

const viewChange = await this.synchronizeViewAndComputeSnapshot(
queryView!
queryView
);
if (viewChange.snapshot) {
newViewSnapshots.push(viewChange.snapshot);
Expand All @@ -995,7 +995,7 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
// allocate the target in LocalStore and initialize a new View.
const target = await this.localStore.getTarget(targetId);
assert(!!target, `Target for id ${targetId} not found`);
targetData = await this.localStore.allocateTarget(target!);
targetData = await this.localStore.allocateTarget(target);
await this.initializeViewAndComputeSnapshot(
this.synthesizeTargetToQuery(target!),
targetId,
Expand Down Expand Up @@ -1097,9 +1097,9 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
);
const target = await this.localStore.getTarget(targetId);
assert(!!target, `Query data for active target ${targetId} not found`);
const targetData = await this.localStore.allocateTarget(target!);
const targetData = await this.localStore.allocateTarget(target);
await this.initializeViewAndComputeSnapshot(
this.synthesizeTargetToQuery(target!),
this.synthesizeTargetToQuery(target),
targetData.targetId,
/*current=*/ false
);
Expand Down Expand Up @@ -1151,7 +1151,7 @@ export class SyncEngine implements RemoteSyncer, SharedClientStateSyncer {
for (const query of queries) {
const queryView = this.queryViewsByQuery.get(query);
assert(!!queryView, `No query view found for ${query}`);
keySet = keySet.unionWith(queryView!.view.syncedDocuments);
keySet = keySet.unionWith(queryView.view.syncedDocuments);
}
return keySet;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/firestore/src/local/indexeddb_mutation_queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
mutation.userId === this.userId,
`Unexpected user '${mutation.userId}' for mutation batch ${batchId}`
);
results.push(this.serializer.fromDbMutationBatch(mutation!));
results.push(this.serializer.fromDbMutationBatch(mutation));
});
})
.next(() => results);
Expand Down Expand Up @@ -483,7 +483,7 @@ export class IndexedDbMutationQueue implements MutationQueue {
mutation.userId === this.userId,
`Unexpected user '${mutation.userId}' for mutation batch ${batchId}`
);
results.push(this.serializer.fromDbMutationBatch(mutation!));
results.push(this.serializer.fromDbMutationBatch(mutation));
})
);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/local/indexeddb_persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,7 @@ export class IndexedDbPersistence implements Persistence {
typeof this.document.addEventListener === 'function',
"Expected 'document.addEventListener' to be a function"
);
this.document!.removeEventListener(
this.document.removeEventListener(
'visibilitychange',
this.documentVisibilityHandler
);
Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/local/indexeddb_target_cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ function retrieveMetadata(
);
return globalStore.get(DbTargetGlobal.key).next(metadata => {
assert(metadata !== null, 'Missing metadata row.');
return metadata!;
return metadata;
});
}

Expand Down
8 changes: 4 additions & 4 deletions packages/firestore/src/local/local_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,8 @@ export class LocalStore {
.lookupMutationBatch(txn, batchId)
.next((batch: MutationBatch | null) => {
assert(batch !== null, 'Attempt to reject nonexistent batch!');
affectedKeys = batch!.keys();
return this.mutationQueue.removeMutationBatch(txn, batch!);
affectedKeys = batch.keys();
return this.mutationQueue.removeMutationBatch(txn, batch);
})
.next(() => {
return this.mutationQueue.performConsistencyCheck(txn);
Expand Down Expand Up @@ -746,8 +746,8 @@ export class LocalStore {
);

// Advance the last limbo free snapshot version
const lastLimboFreeSnapshotVersion = targetData!.snapshotVersion;
const updatedTargetData = targetData!.withLastLimboFreeSnapshotVersion(
const lastLimboFreeSnapshotVersion = targetData.snapshotVersion;
const updatedTargetData = targetData.withLastLimboFreeSnapshotVersion(
lastLimboFreeSnapshotVersion
);
this.targetDataByTarget = this.targetDataByTarget.insert(
Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/local/memory_mutation_queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export class MemoryMutationQueue implements MutationQueue {
const mutationBatch = this.findMutationBatch(batchId);
assert(mutationBatch != null, 'Failed to find local mutation batch.');
return PersistencePromise.resolve<DocumentKeySet | null>(
mutationBatch!.keys()
mutationBatch.keys()
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export abstract class RemoteDocumentChangeBuffer {
this._readTime !== undefined,
'Read time is not set. All removeEntry() calls must include a readTime if `trackRemovals` is used.'
);
return this._readTime!;
return this._readTime;
}

/**
Expand Down
8 changes: 4 additions & 4 deletions packages/firestore/src/local/shared_client_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -963,7 +963,7 @@ export class WebStorageSharedClientState implements SharedClientState {
): RemoteClientState | null {
const clientId = this.fromWebStorageClientStateKey(key);
assert(clientId !== null, `Cannot parse client state key '${key}'`);
return RemoteClientState.fromWebStorageEntry(clientId!, value);
return RemoteClientState.fromWebStorageEntry(clientId, value);
}

/**
Expand All @@ -977,8 +977,8 @@ export class WebStorageSharedClientState implements SharedClientState {
const match = this.mutationBatchKeyRe.exec(key);
assert(match !== null, `Cannot parse mutation batch key '${key}'`);

const batchId = Number(match![1]);
const userId = match![2] !== undefined ? match![2] : null;
const batchId = Number(match[1]);
const userId = match[2] !== undefined ? match[2] : null;
return MutationMetadata.fromWebStorageEntry(
new User(userId),
batchId,
Expand All @@ -997,7 +997,7 @@ export class WebStorageSharedClientState implements SharedClientState {
const match = this.queryTargetKeyRe.exec(key);
assert(match !== null, `Cannot parse query target key '${key}'`);

const targetId = Number(match![1]);
const targetId = Number(match[1]);
return QueryTargetMetadata.fromWebStorageEntry(targetId, value);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/local/simple_query_engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export class SimpleQueryEngine implements QueryEngine {

// TODO: Once LocalDocumentsView provides a getCollectionDocuments()
// method, we should call that here and then filter the results.
return this.localDocumentsView!.getDocumentsMatchingQuery(
return this.localDocumentsView.getDocumentsMatchingQuery(
transaction,
query,
SnapshotVersion.MIN
Expand Down
5 changes: 2 additions & 3 deletions packages/firestore/src/model/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -654,12 +654,11 @@ export class TransformMutation extends Mutation {
maybeDoc instanceof Document,
'Unknown MaybeDocument type ' + maybeDoc
);
const doc = maybeDoc! as Document;
assert(
doc.key.isEqual(this.key),
maybeDoc.key.isEqual(this.key),
'Can only transform a document with the same key'
);
return doc;
return maybeDoc;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/model/transform_operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export class NumericIncrementTransformOperation implements TransformOperation {
transformResult !== null,
"Didn't receive transformResult for NUMERIC_ADD transform"
);
return transformResult!;
return transformResult;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/remote/datastore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export class Datastore {
keys.forEach(key => {
const doc = docs.get(key);
assert(!!doc, 'Missing entity in write response for ' + key);
result.push(doc!);
result.push(doc);
});
return result;
});
Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/src/remote/persistent_stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ export class PersistentWriteStream extends PersistentStream<
!!responseProto.streamToken,
'Got a write response without a stream token'
);
this.lastStreamToken = responseProto.streamToken!;
this.lastStreamToken = responseProto.streamToken;

if (!this.handshakeComplete_) {
// The first response is always the handshake response
Expand Down
20 changes: 10 additions & 10 deletions packages/firestore/src/remote/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,9 @@ export class JsonProtoSerializer {
let nanos = 0;
const fraction = ISO_REG_EXP.exec(utc);
assert(!!fraction, 'invalid timestamp: ' + utc);
if (fraction![1]) {
if (fraction[1]) {
// Pad the fraction out to 9 digits (nanos).
let nanoStr = fraction![1];
let nanoStr = fraction[1];
nanoStr = (nanoStr + '000000000').substr(0, 9);
nanos = Number(nanoStr);
}
Expand Down Expand Up @@ -595,11 +595,11 @@ export class JsonProtoSerializer {
!!doc.found,
'Tried to deserialize a found document from a missing document.'
);
assertPresent(doc.found!.name, 'doc.found.name');
assertPresent(doc.found!.updateTime, 'doc.found.updateTime');
const key = this.fromName(doc.found!.name!);
const version = this.fromVersion(doc.found!.updateTime!);
return new Document(key, version, {}, undefined, doc.found!, v =>
assertPresent(doc.found.name, 'doc.found.name');
assertPresent(doc.found.updateTime, 'doc.found.updateTime');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to punt, but could we magic up assertPresent() to get rid of the remaining ! usage below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. Do you want to take another look?

const key = this.fromName(doc.found.name!);
const version = this.fromVersion(doc.found.updateTime!);
return new Document(key, version, {}, undefined, doc.found, v =>
this.fromValue(v)
);
}
Expand All @@ -613,8 +613,8 @@ export class JsonProtoSerializer {
!!result.readTime,
'Tried to deserialize a missing document without a read time.'
);
const key = this.fromName(result.missing!);
const version = this.fromVersion(result.readTime!);
const key = this.fromName(result.missing);
const version = this.fromVersion(result.readTime);
return new NoDocument(key, version);
}

Expand Down Expand Up @@ -950,7 +950,7 @@ export class JsonProtoSerializer {
commitTime !== undefined,
'Received a write result without a commit time'
);
return protos.map(proto => this.fromWriteResult(proto, commitTime!));
return protos.map(proto => this.fromWriteResult(proto, commitTime));
} else {
return [];
}
Expand Down
6 changes: 3 additions & 3 deletions packages/firestore/src/remote/stream_bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,22 @@ export class StreamBridge<I, O> implements Stream<I, O> {
this.wrappedOnOpen !== undefined,
'Cannot call onOpen because no callback was set'
);
this.wrappedOnOpen!();
this.wrappedOnOpen();
}

callOnClose(err?: FirestoreError): void {
assert(
this.wrappedOnClose !== undefined,
'Cannot call onClose because no callback was set'
);
this.wrappedOnClose!(err);
this.wrappedOnClose(err);
}

callOnMessage(msg: O): void {
assert(
this.wrappedOnMessage !== undefined,
'Cannot call onMessage because no callback was set'
);
this.wrappedOnMessage!(msg);
this.wrappedOnMessage(msg);
}
}
2 changes: 1 addition & 1 deletion packages/firestore/src/util/assert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function fail(failure: string): never {
* Fails if the given assertion condition is false, throwing an Error with the
* given message if it did.
*/
export function assert(assertion: boolean, message: string): void {
export function assert(assertion: boolean, message: string): asserts assertion {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it!

if (!assertion) {
fail(message);
}
Expand Down
8 changes: 4 additions & 4 deletions packages/firestore/test/unit/local/local_store.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,9 @@ class LocalStoreTester {
this.lastChanges !== null,
'Called toReturnChanged() without prior after()'
);
expect(this.lastChanges!.size).to.equal(docs.length, 'number of changes');
expect(this.lastChanges.size).to.equal(docs.length, 'number of changes');
for (const doc of docs) {
const returned = this.lastChanges!.get(doc.key);
const returned = this.lastChanges.get(doc.key);
expectEqual(
doc,
returned,
Expand All @@ -322,12 +322,12 @@ class LocalStoreTester {
this.lastChanges !== null,
'Called toReturnRemoved() without prior after()'
);
expect(this.lastChanges!.size).to.equal(
expect(this.lastChanges.size).to.equal(
keyStrings.length,
'Number of actual changes mismatched number of expected changes'
);
for (const keyString of keyStrings) {
const returned = this.lastChanges!.get(key(keyString));
const returned = this.lastChanges.get(key(keyString));
expect(returned).to.be.an.instanceof(NoDocument);
}
this.lastChanges = null;
Expand Down
2 changes: 1 addition & 1 deletion packages/firestore/test/util/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ export function documentSet(...args: unknown[]): DocumentSet {
}
for (const doc of args) {
assert(doc instanceof Document, 'Bad argument, expected Document: ' + doc);
docSet = docSet.add(doc as Document);
docSet = docSet.add(doc);
}
return docSet;
}
Expand Down