Skip to content

Commit b27b9e4

Browse files
committed
Improve anonymizer return type
The anonymizer function can now return a _recursive partial_ of the input type. So any properties can be omitted in the state property directly or in any nested object. Note that for primitive values and arrays, the return type must still match the state. Similarly, any objects still need to be returned as objects, though they're allowed to have a few less properties.
1 parent 94a1d30 commit b27b9e4

File tree

1 file changed

+16
-5
lines changed

1 file changed

+16
-5
lines changed

src/BaseControllerV2.ts

+16-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,18 @@ enablePatches();
1111
*/
1212
export type Listener<T> = (state: T, patches: Patch[]) => void;
1313

14-
export type Anonymizer<T> = (value: T) => T;
14+
type Primitive = boolean | string | number | null;
15+
16+
// Based upon this StackOverflow answer: https://stackoverflow.com/a/64060332
17+
type RecursivePartial<T> = {
18+
[P in keyof T]?:
19+
T[P] extends (infer U)[] ? RecursivePartial<U>[] :
20+
// eslint-disable-next-line @typescript-eslint/ban-types
21+
T[P] extends Primitive ? T[P] :
22+
RecursivePartial<T>;
23+
};
24+
25+
export type Anonymizer<T> = (value: T) => T extends Primitive ? T : RecursivePartial<T>;
1526

1627
export type StateMetadata<T> = {
1728
[P in keyof T]: {
@@ -109,7 +120,7 @@ function isAnonymizingFunction<T>(x: boolean | Anonymizer<T>): x is Anonymizer<T
109120
return typeof x === 'function';
110121
}
111122

112-
export function getAnonymizedState<S extends Record<string, any>>(state: S, metadata: StateMetadata<S>) {
123+
export function getAnonymizedState<S extends Record<string, any>>(state: S, metadata: StateMetadata<S>): RecursivePartial<S> {
113124
return Object.keys(state).reduce((anonymizedState, _key) => {
114125
const key: keyof S = _key; // https://stackoverflow.com/questions/63893394/string-cannot-be-used-to-index-type-t
115126
const metadataValue = metadata[key].anonymous;
@@ -119,15 +130,15 @@ export function getAnonymizedState<S extends Record<string, any>>(state: S, meta
119130
anonymizedState[key] = state[key];
120131
}
121132
return anonymizedState;
122-
}, {} as Partial<S>);
133+
}, {} as RecursivePartial<S>);
123134
}
124135

125-
export function getPersistentState<S extends Record<string, any>>(state: S, metadata: StateMetadata<S>) {
136+
export function getPersistentState<S extends Record<string, any>>(state: S, metadata: StateMetadata<S>): RecursivePartial<S> {
126137
return Object.keys(state).reduce((persistedState, _key) => {
127138
const key: keyof S = _key; // https://stackoverflow.com/questions/63893394/string-cannot-be-used-to-index-type-t
128139
if (metadata[key].persist) {
129140
persistedState[key] = state[key];
130141
}
131142
return persistedState;
132-
}, {} as Partial<S>);
143+
}, {} as RecursivePartial<S>);
133144
}

0 commit comments

Comments
 (0)