Skip to content

Commit 1450b76

Browse files
author
Brian Chen
committed
Allow type T in WithFieldValue<T>
1 parent 1048c4f commit 1450b76

File tree

5 files changed

+65
-22
lines changed

5 files changed

+65
-22
lines changed

.changeset/short-mice-itch.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@firebase/firestore': minor
3+
---
4+
5+
Expanded `Firestore.WithFieldValue<T>` to include `T`. This allows developers to delegate `WithFieldValue<T>` inside a wrappers of type `T` to avoid exposing Firebase types beyond Firebase-specific logic.

common/api-review/firestore-lite.api.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,7 @@ export function orderBy(fieldPath: string | FieldPath, directionStr?: OrderByDir
204204
export type OrderByDirection = 'desc' | 'asc';
205205

206206
// @public
207-
export type PartialWithFieldValue<T> = T extends Primitive ? T : T extends {} ? {
208-
[K in keyof T]?: PartialWithFieldValue<T[K]> | FieldValue;
209-
} : Partial<T>;
207+
export type PartialWithFieldValue<T> = Partial<WithFieldValue<T>>;
210208

211209
// @public
212210
export type Primitive = string | number | boolean | undefined | null;
@@ -352,9 +350,9 @@ export function where(fieldPath: string | FieldPath, opStr: WhereFilterOp, value
352350
export type WhereFilterOp = '<' | '<=' | '==' | '!=' | '>=' | '>' | 'array-contains' | 'in' | 'array-contains-any' | 'not-in';
353351

354352
// @public
355-
export type WithFieldValue<T> = T extends Primitive ? T : T extends {} ? {
353+
export type WithFieldValue<T> = T | (T extends Primitive ? T : T extends {} ? {
356354
[K in keyof T]: WithFieldValue<T[K]> | FieldValue;
357-
} : Partial<T>;
355+
} : Partial<T>);
358356

359357
// @public
360358
export class WriteBatch {

common/api-review/firestore.api.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,7 @@ export function orderBy(fieldPath: string | FieldPath, directionStr?: OrderByDir
328328
export type OrderByDirection = 'desc' | 'asc';
329329

330330
// @public
331-
export type PartialWithFieldValue<T> = T extends Primitive ? T : T extends {} ? {
332-
[K in keyof T]?: PartialWithFieldValue<T[K]> | FieldValue;
333-
} : Partial<T>;
331+
export type PartialWithFieldValue<T> = Partial<WithFieldValue<T>>;
334332

335333
// @public
336334
export interface PersistenceSettings {
@@ -504,9 +502,9 @@ export function where(fieldPath: string | FieldPath, opStr: WhereFilterOp, value
504502
export type WhereFilterOp = '<' | '<=' | '==' | '!=' | '>=' | '>' | 'array-contains' | 'in' | 'array-contains-any' | 'not-in';
505503

506504
// @public
507-
export type WithFieldValue<T> = T extends Primitive ? T : T extends {} ? {
505+
export type WithFieldValue<T> = T | (T extends Primitive ? T : T extends {} ? {
508506
[K in keyof T]: WithFieldValue<T[K]> | FieldValue;
509-
} : Partial<T>;
507+
} : Partial<T>);
510508

511509
// @public
512510
export class WriteBatch {

packages/firestore/src/lite-api/reference.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,19 @@ export interface DocumentData {
5454
* Similar to Typescript's `Partial<T>`, but allows nested fields to be
5555
* omitted and FieldValues to be passed in as property values.
5656
*/
57-
export type PartialWithFieldValue<T> = T extends Primitive
58-
? T
59-
: T extends {}
60-
? { [K in keyof T]?: PartialWithFieldValue<T[K]> | FieldValue }
61-
: Partial<T>;
57+
export type PartialWithFieldValue<T> = Partial<WithFieldValue<T>>;
6258

6359
/**
6460
* Allows FieldValues to be passed in as a property value while maintaining
6561
* type safety.
6662
*/
67-
export type WithFieldValue<T> = T extends Primitive
68-
? T
69-
: T extends {}
70-
? { [K in keyof T]: WithFieldValue<T[K]> | FieldValue }
71-
: Partial<T>;
72-
63+
export type WithFieldValue<T> =
64+
| T
65+
| (T extends Primitive
66+
? T
67+
: T extends {}
68+
? { [K in keyof T]: WithFieldValue<T[K]> | FieldValue }
69+
: Partial<T>);
7370
/**
7471
* Update data (for use with {@link (updateDoc:1)}) that consists of field paths
7572
* (e.g. 'foo' or 'foo.baz') mapped to values. Fields that contain dots

packages/firestore/test/lite/integration.test.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ describe('withConverter() support', () => {
12861286
}
12871287
};
12881288

1289-
describe('NestedPartial', () => {
1289+
describe('nested partial support', () => {
12901290
const testConverterMerge = {
12911291
toFirestore(
12921292
testObj: PartialWithFieldValue<TestObject>,
@@ -1496,6 +1496,51 @@ describe('withConverter() support', () => {
14961496
});
14971497
});
14981498
});
1499+
1500+
describe('used as a type', () => {
1501+
class ObjectWrapper<T> {
1502+
withFieldValueT(value: WithFieldValue<T>): void {
1503+
// eslint-disable-next-line no-console
1504+
console.log(value);
1505+
}
1506+
1507+
withPartialFieldValueT(value: PartialWithFieldValue<T>): void {
1508+
// eslint-disable-next-line no-console
1509+
console.log(value);
1510+
}
1511+
1512+
// Wrapper to avoid having Firebase types in non-Firebase code.
1513+
withT(value: T): void {
1514+
this.withFieldValueT(value);
1515+
}
1516+
1517+
// Wrapper to avoid having Firebase types in non-Firebase code.
1518+
withPartialT(value: Partial<T>): void {
1519+
this.withPartialFieldValueT(value);
1520+
}
1521+
}
1522+
1523+
it('supports passing in the object as `T`', () => {
1524+
interface Foo {
1525+
id: string;
1526+
foo: number;
1527+
}
1528+
const foo = new ObjectWrapper<Foo>();
1529+
foo.withFieldValueT({ id: '', foo: increment(1) });
1530+
foo.withPartialFieldValueT({ foo: increment(1) });
1531+
foo.withT({ id: '', foo: 1 });
1532+
foo.withPartialT({ foo: 1 });
1533+
});
1534+
1535+
it('does not allow primitive types to use FieldValue', () => {
1536+
type Bar = number;
1537+
const bar = new ObjectWrapper<Bar>();
1538+
// @ts-expect-error
1539+
bar.withFieldValueT(increment(1));
1540+
// @ts-expect-error
1541+
bar.withPartialFieldValueT(increment(1));
1542+
});
1543+
});
14991544
});
15001545

15011546
describe('UpdateData', () => {

0 commit comments

Comments
 (0)