Skip to content

Commit 768516c

Browse files
authored
Merge pull request #128 from TNG/feature-117-3
#117: Strict TypeScript mode
2 parents c762650 + c3c0c54 commit 768516c

17 files changed

Lines changed: 91 additions & 69 deletions

projects/ngqp/core/src/lib/accessors/multi-select-control-value-accessor.directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class MultiSelectControlValueAccessorDirective<T> implements ControlValue
2929
this.selectedIds = Array.from(this.options.entries())
3030
.filter(([id, option]) => option.selected)
3131
.map(([id]) => id);
32-
const values = this.selectedIds.map(id => this.optionMap.get(id));
32+
const values = this.selectedIds.map(id => this.optionMap.get(id)!);
3333
this.fnChange(values);
3434
}
3535

@@ -49,7 +49,7 @@ export class MultiSelectControlValueAccessorDirective<T> implements ControlValue
4949

5050
this.selectedIds = values
5151
.map(value => this.getOptionId(value))
52-
.filter(id => id !== null);
52+
.filter((id: string | null): id is string => id !== null);
5353
this.options.forEach((option, id) => option.selected = this.selectedIds.includes(id));
5454
}
5555

projects/ngqp/core/src/lib/accessors/multi-select-option.directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ export class MultiSelectOptionDirective<T> implements OnInit, OnDestroy {
2727

2828
public ngOnDestroy() {
2929
if (this.parent) {
30-
this.parent.deregisterOption(this.id);
30+
this.parent.deregisterOption(this.id!);
3131
}
3232
}
3333

3434
@Input('value')
3535
public set value(value: T) {
3636
if (this.parent) {
37-
this.parent.updateOptionValue(this.id, value);
37+
this.parent.updateOptionValue(this.id!, value);
3838
}
3939
}
4040

projects/ngqp/core/src/lib/accessors/number-control-value-accessor.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const NGQP_NUMBER_VALUE_ACCESSOR: any = {
1515
})
1616
export class NumberControlValueAccessorDirective implements ControlValueAccessor {
1717

18-
private fnChange = (_: number) => {};
18+
private fnChange = (_: number | null) => {};
1919
private fnTouched = () => {};
2020

2121
@HostListener('input', ['$event'])

projects/ngqp/core/src/lib/accessors/range-control-value-accessor.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const NGQP_RANGE_VALUE_ACCESSOR: any = {
1515
})
1616
export class RangeControlValueAccessorDirective implements ControlValueAccessor {
1717

18-
private fnChange = (_: number) => {};
18+
private fnChange = (_: number | null) => {};
1919
private fnTouched = () => {};
2020

2121
@HostListener('input', ['$event'])

projects/ngqp/core/src/lib/accessors/select-control-value-accessor.directive.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Directive, ElementRef, forwardRef, HostListener, Renderer2, StaticProvider } from '@angular/core';
22
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
3+
import { undefinedToNull } from '../util';
34

45
/** @ignore */
56
export const NGQP_SELECT_VALUE_ACCESSOR: StaticProvider = {
@@ -20,13 +21,13 @@ export class SelectControlValueAccessorDirective<T> implements ControlValueAcces
2021
private optionMap = new Map<string, T>();
2122

2223
private idCounter = 0;
23-
private fnChange = (_: T) => {};
24+
private fnChange = (_: T | null) => {};
2425
private fnTouched = () => {};
2526

2627
@HostListener('change', ['$event'])
2728
public onChange(event: UIEvent) {
2829
this.selectedId = (event.target as HTMLOptionElement).value;
29-
this.value = this.optionMap.get(this.selectedId);
30+
this.value = undefinedToNull(this.optionMap.get(this.selectedId));
3031
this.fnChange(this.value);
3132
}
3233

@@ -38,10 +39,10 @@ export class SelectControlValueAccessorDirective<T> implements ControlValueAcces
3839
constructor(private renderer: Renderer2, private elementRef: ElementRef<HTMLSelectElement>) {
3940
}
4041

41-
public writeValue(value: T) {
42+
public writeValue(value: T | null) {
4243
this.value = value;
4344

44-
this.selectedId = this.getOptionId(value);
45+
this.selectedId = value === null ? null : this.getOptionId(value);
4546
if (this.selectedId === null) {
4647
this.renderer.setProperty(this.elementRef.nativeElement, 'selectedIndex', -1);
4748
}

projects/ngqp/core/src/lib/accessors/select-option.directive.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ export class SelectOptionDirective<T> implements OnInit, OnDestroy {
2727

2828
public ngOnDestroy() {
2929
if (this.parent) {
30-
this.parent.deregisterOption(this.id);
30+
this.parent.deregisterOption(this.id!);
3131
this.parent.writeValue(this.parent.value);
3232
}
3333
}
3434

3535
@Input('value')
3636
public set value(value: T) {
3737
if (this.parent) {
38-
this.parent.updateOptionValue(this.id, value);
38+
this.parent.updateOptionValue(this.id!, value);
3939
this.parent.writeValue(this.parent.value);
4040
}
4141
}

projects/ngqp/core/src/lib/accessors/util.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import { NGQP_BUILT_IN_ACCESSORS } from './ngqp-accessors';
1010
*
1111
* @internal
1212
*/
13-
export function selectValueAccessor(valueAccessors: ControlValueAccessor[]): ControlValueAccessor | null {
13+
export function selectValueAccessor(valueAccessors: ControlValueAccessor[]): ControlValueAccessor {
1414
if (!valueAccessors || !Array.isArray(valueAccessors)) {
15-
return null;
15+
throw new Error(`No matching ControlValueAccessor has been found for this form control`);
1616
}
1717

1818
let defaultAccessor: ControlValueAccessor | null = null;

projects/ngqp/core/src/lib/directives/query-param-group.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class QueryParamGroupDirective implements OnChanges {
2020
* The {@link QueryParamGroup} to bind.
2121
*/
2222
@Input('queryParamGroup')
23-
public queryParamGroup: QueryParamGroup;
23+
public queryParamGroup: QueryParamGroup | null = null;
2424

2525
/** @internal */
2626
constructor(private groupService: QueryParamGroupService) {

projects/ngqp/core/src/lib/directives/query-param-group.service.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class NavigationData {
4242
export class QueryParamGroupService implements OnDestroy {
4343

4444
/** The {@link QueryParamGroup} to bind. */
45-
private queryParamGroup: QueryParamGroup;
45+
private queryParamGroup: QueryParamGroup | null = null;
4646

4747
/** List of {@link QueryParamAccessor} registered to this service. */
4848
private directives = new Map<string, QueryParamAccessor[]>();
@@ -122,7 +122,7 @@ export class QueryParamGroupService implements OnDestroy {
122122
})
123123
).pipe(
124124
// Do not synchronize while the param is detached from the group
125-
filter(() => !!this.queryParamGroup.get(queryParamName)),
125+
filter(() => !!this.getQueryParamGroup().get(queryParamName)),
126126
map((newValue: unknown[]) => this.getParamsForValue(partitionedQueryParam, partitionedQueryParam.reduce(newValue))),
127127
takeUntil(this.destroy$),
128128
).subscribe(params => this.enqueueNavigation(new NavigationData(params)));
@@ -154,7 +154,7 @@ export class QueryParamGroupService implements OnDestroy {
154154
});
155155

156156
this.directives.delete(queryParamName);
157-
const queryParam = this.queryParamGroup.get(queryParamName);
157+
const queryParam = this.getQueryParamGroup().get(queryParamName);
158158
if (queryParam) {
159159
queryParam._clearChangeFunctions();
160160
}
@@ -170,10 +170,14 @@ export class QueryParamGroupService implements OnDestroy {
170170

171171
/** Listens for programmatic changes on group level and synchronizes to the router. */
172172
private setupGroupChangeListener(): void {
173-
this.queryParamGroup._registerOnChange((newValue: Record<string, unknown>) => {
173+
this.getQueryParamGroup()._registerOnChange((newValue: Record<string, unknown> | null) => {
174+
if (newValue === null) {
175+
throw new Error(`Received null value from QueryParamGroup.`);
176+
}
177+
174178
let params: Params = {};
175179
Object.keys(newValue).forEach(queryParamName => {
176-
const queryParam = this.queryParamGroup.get(queryParamName);
180+
const queryParam = this.getQueryParamGroup().get(queryParamName);
177181
if (isMissing(queryParam)) {
178182
return;
179183
}
@@ -187,12 +191,12 @@ export class QueryParamGroupService implements OnDestroy {
187191

188192
/** Listens for programmatic changes on parameter level and synchronizes to the router. */
189193
private setupParamChangeListeners(): void {
190-
Object.keys(this.queryParamGroup.queryParams)
194+
Object.keys(this.getQueryParamGroup().queryParams)
191195
.forEach(queryParamName => this.setupParamChangeListener(queryParamName));
192196
}
193197

194198
private setupParamChangeListener(queryParamName: string): void {
195-
const queryParam = this.queryParamGroup.get(queryParamName);
199+
const queryParam = this.getQueryParamGroup().get(queryParamName);
196200
if (!queryParam) {
197201
throw new Error(`No param in group found for name ${queryParamName}`);
198202
}
@@ -211,7 +215,7 @@ export class QueryParamGroupService implements OnDestroy {
211215
// particular group; however, we do need to react if one of our parameters has
212216
// vanished when it was set before.
213217
distinctUntilChanged((previousMap, currentMap) => {
214-
const keys = Object.values(this.queryParamGroup.queryParams)
218+
const keys = Object.values(this.getQueryParamGroup().queryParams)
215219
.map(queryParam => this.wrapIntoPartition(queryParam))
216220
.map(partitionedQueryParam => partitionedQueryParam.queryParams.map(queryParam => queryParam.urlParam))
217221
.reduce((a, b) => [...a, ...b], []);
@@ -227,9 +231,9 @@ export class QueryParamGroupService implements OnDestroy {
227231
const synthetic = this.isSyntheticNavigation();
228232
const groupValue: Record<string, unknown> = {};
229233

230-
Object.keys(this.queryParamGroup.queryParams).forEach(queryParamName => {
234+
Object.keys(this.getQueryParamGroup().queryParams).forEach(queryParamName => {
231235
const partitionedQueryParam = this.getQueryParamAsPartition(queryParamName);
232-
const newValues = partitionedQueryParam.queryParams.map(queryParam => isMultiQueryParam(queryParam)
236+
const newValues = partitionedQueryParam.queryParams.map(queryParam => isMultiQueryParam<unknown>(queryParam)
233237
? queryParam.deserializeValue(queryParamMap.getAll(queryParam.urlParam))
234238
: queryParam.deserializeValue(queryParamMap.get(queryParam.urlParam))
235239
);
@@ -243,7 +247,7 @@ export class QueryParamGroupService implements OnDestroy {
243247
groupValue[ queryParamName ] = newValue;
244248
});
245249

246-
this.queryParamGroup.setValue(groupValue, {
250+
this.getQueryParamGroup().setValue(groupValue, {
247251
emitEvent: !synthetic,
248252
emitModelToViewChange: false,
249253
});
@@ -252,7 +256,7 @@ export class QueryParamGroupService implements OnDestroy {
252256

253257
/** Listens for newly added parameters and starts synchronization for them. */
254258
private watchNewParams(): void {
255-
this.queryParamGroup.queryParamAdded$.pipe(
259+
this.getQueryParamGroup().queryParamAdded$.pipe(
256260
takeUntil(this.destroy$)
257261
).subscribe(queryParamName => {
258262
this.setupParamChangeListener(queryParamName);
@@ -342,7 +346,7 @@ export class QueryParamGroupService implements OnDestroy {
342346
* This merges the global configuration with the group specific configuration.
343347
*/
344348
private get routerOptions(): RouterOptions {
345-
const groupOptions = this.queryParamGroup ? this.queryParamGroup.routerOptions : {};
349+
const groupOptions = this.getQueryParamGroup().routerOptions;
346350

347351
return {
348352
...(this.globalRouterOptions || {}),
@@ -358,7 +362,7 @@ export class QueryParamGroupService implements OnDestroy {
358362
* query parameters independent of whether they are partitioned.
359363
*/
360364
private getQueryParamAsPartition(queryParamName: string): PartitionedQueryParam<unknown> {
361-
const queryParam = this.queryParamGroup.get(queryParamName);
365+
const queryParam = this.getQueryParamGroup().get(queryParamName);
362366
if (!queryParam) {
363367
throw new Error(`Could not find query param with name ${queryParamName}. Did you forget to add it to your QueryParamGroup?`);
364368
}
@@ -382,4 +386,12 @@ export class QueryParamGroupService implements OnDestroy {
382386
});
383387
}
384388

389+
private getQueryParamGroup(): QueryParamGroup {
390+
if (!this.queryParamGroup) {
391+
throw new Error(`No QueryParamGroup has been registered yet.`);
392+
}
393+
394+
return this.queryParamGroup;
395+
}
396+
385397
}

projects/ngqp/core/src/lib/directives/query-param-name.directive.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,22 @@ export class QueryParamNameDirective implements QueryParamAccessor, OnChanges, O
2121
* Note that this does not refer to the [parameter name]{@link QueryParam#urlParam}.
2222
*/
2323
@Input('queryParamName')
24-
public name: string;
24+
public set name(name: string) {
25+
this._name = name;
26+
}
27+
28+
public get name(): string {
29+
if (!this._name) {
30+
throw new Error(`No queryParamName has been specified.`);
31+
}
32+
33+
return this._name;
34+
}
2535

2636
/** @internal */
27-
public valueAccessor: ControlValueAccessor | null = null;
37+
public valueAccessor: ControlValueAccessor;
38+
39+
private _name: string | null = null;
2840

2941
/** @internal */
3042
constructor(

0 commit comments

Comments
 (0)