Skip to content

Commit 104602c

Browse files
Cast
1 parent 92f5142 commit 104602c

File tree

3 files changed

+38
-21
lines changed

3 files changed

+38
-21
lines changed

packages/firestore/src/remote/datastore.ts

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { MaybeDocument } from '../model/document';
2020
import { DocumentKey } from '../model/document_key';
2121
import { Mutation, MutationResult } from '../model/mutation';
2222
import * as api from '../protos/firestore_proto_api';
23-
import { debugAssert, hardAssert } from '../util/assert';
23+
import { debugCast, hardAssert } from '../util/assert';
2424
import { Code, FirestoreError } from '../util/error';
2525
import { Connection } from './connection';
2626
import { JsonProtoSerializer } from './serializer';
@@ -102,11 +102,7 @@ export async function invokeCommitRpc(
102102
datastore: Datastore,
103103
mutations: Mutation[]
104104
): Promise<MutationResult[]> {
105-
debugAssert(
106-
datastore instanceof DatastoreImpl,
107-
'invokeCommitRpc() requires DatastoreImpl'
108-
);
109-
const datastoreImpl: DatastoreImpl = datastore;
105+
const datastoreImpl = debugCast(datastore, DatastoreImpl);
110106
const params = {
111107
database: datastoreImpl.serializer.encodedDatabaseId,
112108
writes: mutations.map(m => datastoreImpl.serializer.toMutation(m))
@@ -125,11 +121,7 @@ export async function invokeBatchGetDocumentsRpc(
125121
datastore: Datastore,
126122
keys: DocumentKey[]
127123
): Promise<MaybeDocument[]> {
128-
debugAssert(
129-
datastore instanceof DatastoreImpl,
130-
'invokeBatchGetDocumentsRpc() requires DatastoreImpl'
131-
);
132-
const datastoreImpl: DatastoreImpl = datastore;
124+
const datastoreImpl = debugCast(datastore, DatastoreImpl);
133125
const params = {
134126
database: datastoreImpl.serializer.encodedDatabaseId,
135127
documents: keys.map(k => datastoreImpl.serializer.toName(k))
@@ -158,11 +150,7 @@ export function newPersistentWriteStream(
158150
queue: AsyncQueue,
159151
listener: WriteStreamListener
160152
): PersistentWriteStream {
161-
debugAssert(
162-
datastore instanceof DatastoreImpl,
163-
'newPersistentWriteStream() requires DatastoreImpl'
164-
);
165-
const datastoreImpl: DatastoreImpl = datastore;
153+
const datastoreImpl = debugCast(datastore, DatastoreImpl);
166154
return new PersistentWriteStream(
167155
queue,
168156
datastoreImpl.connection,
@@ -177,11 +165,7 @@ export function newPersistentWatchStream(
177165
queue: AsyncQueue,
178166
listener: WatchStreamListener
179167
): PersistentListenStream {
180-
debugAssert(
181-
datastore instanceof DatastoreImpl,
182-
'newPersistentWatchStream() requires DatastoreImpl'
183-
);
184-
const datastoreImpl: DatastoreImpl = datastore;
168+
const datastoreImpl = debugCast(datastore, DatastoreImpl);
185169
return new PersistentListenStream(
186170
queue,
187171
datastoreImpl.connection,

packages/firestore/src/util/assert.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,19 @@ export function debugAssert(
7070
fail(message);
7171
}
7272
}
73+
74+
/**
75+
* Casts `obj` to `T`. In non-production builds, verifies that `obj` is an
76+
* instance of `T` before casting.
77+
*/
78+
export function debugCast<T>(
79+
obj: object,
80+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
81+
constructor: { new (...args: any[]): T }
82+
): T {
83+
debugAssert(
84+
obj instanceof constructor,
85+
`Expected type '${constructor.name}', but was '${obj.constructor.name}'`
86+
);
87+
return obj as T;
88+
}

packages/firestore/test/unit/util/misc.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,27 @@
1717

1818
import { expect } from 'chai';
1919
import { immediateSuccessor } from '../../../src/util/misc';
20+
import { debugCast } from '../../../src/util/assert';
2021

2122
describe('immediateSuccessor', () => {
2223
it('generates the correct immediate successors', () => {
2324
expect(immediateSuccessor('hello')).to.equal('hello\0');
2425
expect(immediateSuccessor('')).to.equal('\0');
2526
});
2627
});
28+
29+
describe('typeCast', () => {
30+
it('can cast types', () => {
31+
class Foo {}
32+
class Bar extends Foo {}
33+
const foo: Foo = new Bar();
34+
const bar: Bar = debugCast(foo, Bar);
35+
});
36+
37+
it.only('validates types', () => {
38+
class Foo {}
39+
class Bar {}
40+
const foo = new Foo();
41+
expect(debugCast(foo, Bar)).to.throw("Expected type 'Bar', but was 'Foo'");
42+
});
43+
});

0 commit comments

Comments
 (0)