Skip to content

Commit 9eac43c

Browse files
JeanMechemmalerba
authored andcommitted
feat(common): Support of optional keys for the KeyValue pipe (angular#48814)
This commit is extending the capabilities of the KeyValue pipe by allowing interfaces with optional keys. fixes angular#46867 PR Close angular#48814
1 parent dd7c4cd commit 9eac43c

File tree

3 files changed

+62
-0
lines changed

3 files changed

+62
-0
lines changed

goldens/public-api/common/index.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ export class KeyValuePipe implements PipeTransform {
390390
// (undocumented)
391391
transform<K extends string, V>(input: Record<K, V> | ReadonlyMap<K, V> | null | undefined, compareFn?: ((a: KeyValue<K, V>, b: KeyValue<K, V>) => number) | null): Array<KeyValue<K, V>> | null;
392392
// (undocumented)
393+
transform<T>(input: T, compareFn?: T extends object ? (a: T[keyof T], b: T[keyof T]) => number : never): T extends object ? Array<KeyValue<keyof T, T[keyof T]>> : null;
394+
// (undocumented)
393395
static ɵfac: i0.ɵɵFactoryDeclaration<KeyValuePipe, never>;
394396
// (undocumented)
395397
static ɵpipe: i0.ɵɵPipeDeclaration<KeyValuePipe, "keyvalue", true>;

packages/common/src/pipes/keyvalue_pipe.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,17 @@ export class KeyValuePipe implements PipeTransform {
9292
input: Record<K, V> | null | undefined,
9393
compareFn?: ((a: KeyValue<string, V>, b: KeyValue<string, V>) => number) | null,
9494
): Array<KeyValue<string, V>> | null;
95+
9596
transform<K extends string, V>(
9697
input: Record<K, V> | ReadonlyMap<K, V> | null | undefined,
9798
compareFn?: ((a: KeyValue<K, V>, b: KeyValue<K, V>) => number) | null,
9899
): Array<KeyValue<K, V>> | null;
100+
101+
transform<T>(
102+
input: T,
103+
compareFn?: T extends object ? (a: T[keyof T], b: T[keyof T]) => number : never,
104+
): T extends object ? Array<KeyValue<keyof T, T[keyof T]>> : null;
105+
99106
transform<K, V>(
100107
input: undefined | null | {[key: string]: V; [key: number]: V} | ReadonlyMap<K, V>,
101108
compareFn: ((a: KeyValue<K, V>, b: KeyValue<K, V>) => number) | null = defaultComparator,

packages/common/test/pipes/keyvalue_pipe_spec.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,59 @@ describe('KeyValuePipe', () => {
9999
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
100100
expect(pipe.transform(value)).toEqual(null);
101101
});
102+
103+
it('should accept an object with optional keys', () => {
104+
interface MyInterface {
105+
one: string;
106+
two: number;
107+
three: string;
108+
four: string;
109+
}
110+
const myData: Partial<MyInterface> = {
111+
one: 'One',
112+
two: 2,
113+
three: undefined,
114+
};
115+
116+
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
117+
expect(pipe.transform(myData)?.length).toEqual(3);
118+
119+
const differ = (a: string | number | undefined, b: string | number | undefined): number => {
120+
return 1;
121+
};
122+
expect(pipe.transform(myData, differ)?.length).toEqual(3);
123+
});
124+
125+
it('should accept an nullable object with optional keys', () => {
126+
interface MyInterface {
127+
one?: string;
128+
two?: string;
129+
three?: string;
130+
}
131+
132+
let value!: MyInterface | null;
133+
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
134+
expect(pipe.transform(value)).toEqual(null);
135+
});
136+
137+
it('should accept an nullable object with optional keys', () => {
138+
interface MyInterface {
139+
one?: string;
140+
two?: string;
141+
three?: string;
142+
}
143+
144+
const value: MyInterface | null = {};
145+
const pipe = new KeyValuePipe(defaultKeyValueDiffers);
146+
expect(pipe.transform(value)?.length).toEqual(0);
147+
148+
// we use the random condition to make sure the typing includes null (else TS's inference is too smart and strips null)
149+
const value2: MyInterface | null = Math.random() <= 1 ? {one: '1', three: '3'} : null;
150+
const kv = pipe.transform(value2);
151+
expect(kv?.length).toEqual(2);
152+
expect(kv).toContain({key: 'one', value: '1'});
153+
expect(kv).toContain({key: 'three', value: '3'});
154+
});
102155
});
103156

104157
describe('Map', () => {

0 commit comments

Comments
 (0)