diff --git a/aio/src/app/app.component.spec.ts b/aio/src/app/app.component.spec.ts index 8e2e860d87..c1fc933c0a 100644 --- a/aio/src/app/app.component.spec.ts +++ b/aio/src/app/app.component.spec.ts @@ -635,61 +635,53 @@ describe('AppComponent', () => { }); describe('aio-toc', () => { - let tocContainer: HTMLElement|null; - let toc: HTMLElement|null; - - const setHasFloatingToc = (hasFloatingToc: boolean) => { + function setHasFloatingTocAndGetToc(hasFloatingToc: false): [null, null]; + function setHasFloatingTocAndGetToc(hasFloatingToc: true): [HTMLElement, HTMLElement]; + function setHasFloatingTocAndGetToc(hasFloatingToc: boolean) { component.hasFloatingToc = hasFloatingToc; fixture.detectChanges(); - tocContainer = fixture.debugElement.nativeElement.querySelector('.toc-container'); - toc = tocContainer && tocContainer.querySelector('aio-toc'); - }; + const tocContainer = fixture.debugElement.nativeElement.querySelector('.toc-container'); + const toc = tocContainer && tocContainer.querySelector('aio-toc'); - - beforeEach(() => { - tocContainer = null; - toc = null; - }); + return [toc, tocContainer]; + } it('should show/hide `` based on `hasFloatingToc`', () => { - expect(tocContainer).toBeFalsy(); - expect(toc).toBeFalsy(); + const [toc1, tocContainer1] = setHasFloatingTocAndGetToc(true); + expect(tocContainer1).toBeTruthy(); + expect(toc1).toBeTruthy(); - setHasFloatingToc(true); - expect(tocContainer).toBeTruthy(); - expect(toc).toBeTruthy(); - - setHasFloatingToc(false); - expect(tocContainer).toBeFalsy(); - expect(toc).toBeFalsy(); + const [toc2, tocContainer2] = setHasFloatingTocAndGetToc(false); + expect(tocContainer2).toBeFalsy(); + expect(toc2).toBeFalsy(); }); it('should have a non-embedded `` element', () => { - setHasFloatingToc(true); - expect(toc!.classList.contains('embedded')).toBe(false); + const [toc] = setHasFloatingTocAndGetToc(true); + expect(toc.classList.contains('embedded')).toBe(false); }); it('should update the TOC container\'s `maxHeight` based on `tocMaxHeight`', () => { - setHasFloatingToc(true); + const [, tocContainer] = setHasFloatingTocAndGetToc(true); component.tocMaxHeight = '100'; fixture.detectChanges(); - expect(tocContainer!.style.maxHeight).toBe('100px'); + expect(tocContainer.style.maxHeight).toBe('100px'); component.tocMaxHeight = '200'; fixture.detectChanges(); - expect(tocContainer!.style.maxHeight).toBe('200px'); + expect(tocContainer.style.maxHeight).toBe('200px'); }); it('should restrain scrolling inside the ToC container', () => { const restrainScrolling = spyOn(component, 'restrainScrolling'); const evt = new WheelEvent('wheel'); + const [, tocContainer] = setHasFloatingTocAndGetToc(true); - setHasFloatingToc(true); expect(restrainScrolling).not.toHaveBeenCalled(); - tocContainer!.dispatchEvent(evt); + tocContainer.dispatchEvent(evt); expect(restrainScrolling).toHaveBeenCalledWith(evt); }); @@ -697,7 +689,7 @@ describe('AppComponent', () => { const loader = fixture.debugElement.injector.get(ElementsLoader) as unknown as TestElementsLoader; expect(loader.loadCustomElement).not.toHaveBeenCalled(); - setHasFloatingToc(true); + setHasFloatingTocAndGetToc(true); expect(loader.loadCustomElement).toHaveBeenCalledWith('aio-toc'); }); }); @@ -721,7 +713,7 @@ describe('AppComponent', () => { createTestingModule('a/b', 'stable'); await initializeTest(); const banner: HTMLElement = fixture.debugElement.query(By.css('aio-mode-banner')).nativeElement; - expect(banner.textContent!.trim()).toEqual(''); + expect(banner.textContent?.trim()).toEqual(''); }); }); @@ -1355,10 +1347,10 @@ class TestHttpClient { if (/navigation\.json/.test(url)) { data = this.navJson; } else { - const match = /generated\/docs\/(.+)\.json/.exec(url)!; - const id = match[1]!; + const match = /generated\/docs\/(.+)\.json/.exec(url); + const id = match?.[1]; // Make up a title for test purposes - const title = id.split('/').pop()!.replace(/^([a-z])/, (_, letter) => letter.toUpperCase()); + const title = id?.split('/')?.pop()?.replace(/^([a-z])/, (_, letter) => letter.toUpperCase()); const h1 = (id === 'no-title') ? '' : `

${title}

`; const contents = `${h1}

Some heading

`; data = { id, contents }; diff --git a/aio/src/app/app.component.ts b/aio/src/app/app.component.ts index 90a03ae382..c90c41d5c8 100644 --- a/aio/src/app/app.component.ts +++ b/aio/src/app/app.component.ts @@ -163,7 +163,7 @@ export class AppComponent implements OnInit { // Find the current version - eithers title matches the current deployment mode // or its title matches the major version of the current version info this.currentDocVersion = this.docVersions.find(version => - version.title === this.deployment.mode || version.title === `v${versionInfo.major}`)!; + version.title === this.deployment.mode || version.title === `v${versionInfo.major}`) as NavigationNode; this.currentDocVersion.title += ` (v${versionInfo.raw})`; }); diff --git a/aio/src/app/custom-elements/announcement-bar/announcement-bar.component.spec.ts b/aio/src/app/custom-elements/announcement-bar/announcement-bar.component.spec.ts index ddd274d0b2..f18fa9a9b1 100644 --- a/aio/src/app/custom-elements/announcement-bar/announcement-bar.component.spec.ts +++ b/aio/src/app/custom-elements/announcement-bar/announcement-bar.component.spec.ts @@ -102,11 +102,11 @@ describe('AnnouncementBarComponent', () => { }); it('should display an image', () => { - expect(element.querySelector('img')!.src).toContain('dummy/image'); + expect(element.querySelector('img')?.src).toContain('dummy/image'); }); it('should display a link', () => { - expect(element.querySelector('a')!.href).toContain('link/to/website'); + expect(element.querySelector('a')?.href).toContain('link/to/website'); }); }); }); diff --git a/aio/src/app/custom-elements/api/api-list.component.spec.ts b/aio/src/app/custom-elements/api/api-list.component.spec.ts index fb97db2c38..2c33324d5b 100644 --- a/aio/src/app/custom-elements/api/api-list.component.spec.ts +++ b/aio/src/app/custom-elements/api/api-list.component.spec.ts @@ -38,7 +38,7 @@ describe('ApiListComponent', () => { component.filteredSections.subscribe(filtered => { filtered = filtered.filter(section => section.items); expect(filtered.length).toBeGreaterThan(0, 'expected something'); - expect(filtered.every(section => section.items!.every(itemTest))).toBe(true, label); + expect(filtered.every(section => section.items?.every(itemTest))).toBe(true, label); }); } @@ -66,7 +66,7 @@ describe('ApiListComponent', () => { filtered = filtered.filter(section => Array.isArray(section.items)); expect(filtered.length).toBe(1, 'only one section'); expect(filtered[0].name).toBe('core'); - expect(filtered[0].items).toEqual(sections.find(section => section.name === 'core')!.items); + expect(filtered[0].items).toEqual(sections.find(section => section.name === 'core')?.items as ApiItem[]); }); }); @@ -74,8 +74,8 @@ describe('ApiListComponent', () => { it('should null if there are no matching items and the section itself does not match', () => { component.setQuery('core'); component.filteredSections.subscribe(filtered => { - const commonSection = filtered.find(section => section.name === 'common')!; - expect(commonSection.items).toBe(null); + const commonSection = filtered.find(section => section.name === 'common'); + expect(commonSection?.items).toBe(null); }); }); @@ -117,7 +117,7 @@ describe('ApiListComponent', () => { filtered = filtered.filter(s => s.items); expect(filtered.length).toBe(1, 'sections'); expect(filtered[0].name).toBe(section, 'section name'); - const items = filtered[0].items!; + const items = filtered[0].items as ApiItem[]; expect(items.length).toBe(1, 'items'); const item = items[0]; diff --git a/aio/src/app/custom-elements/api/api-list.component.ts b/aio/src/app/custom-elements/api/api-list.component.ts index 836aab8e03..0950f4f29a 100644 --- a/aio/src/app/custom-elements/api/api-list.component.ts +++ b/aio/src/app/custom-elements/api/api-list.component.ts @@ -17,9 +17,9 @@ import { Option } from 'app/shared/select/select.component'; import { map } from 'rxjs/operators'; class SearchCriteria { - query ? = ''; - status ? = 'all'; - type ? = 'all'; + query = ''; + status = 'all'; + type = 'all'; } @Component({ @@ -116,13 +116,13 @@ export class ApiListComponent implements OnInit { const sectionNameMatches = !query || section.name.indexOf(query) !== -1; const matchesQuery = (item: ApiItem) => - sectionNameMatches || item.name.indexOf(query!) !== -1; + sectionNameMatches || item.name.indexOf(query) !== -1; const matchesStatus = (item: ApiItem) => status === 'all' || status === item.stability || (status === 'security-risk' && item.securityRisk); const matchesType = (item: ApiItem) => type === 'all' || type === item.docType; - const items = section.items!.filter(item => + const items: ApiItem[] = (section.items || []).filter(item => matchesType(item) && matchesStatus(item) && matchesQuery(item)); // If there are no items we still return an empty array if the section name matches and the type is 'package' @@ -160,7 +160,7 @@ export class ApiListComponent implements OnInit { this.locationService.setSearch('API Search', params); } - private setSearchCriteria(criteria: SearchCriteria) { + private setSearchCriteria(criteria: Partial) { this.criteriaSubject.next(Object.assign(this.searchCriteria, criteria)); this.setLocationSearch(); } diff --git a/aio/src/app/custom-elements/code/code.component.spec.ts b/aio/src/app/custom-elements/code/code.component.spec.ts index 1a93817245..88223c218b 100644 --- a/aio/src/app/custom-elements/code/code.component.spec.ts +++ b/aio/src/app/custom-elements/code/code.component.spec.ts @@ -251,7 +251,7 @@ describe('CodeComponent', () => { actualCode = spy.calls.mostRecent().args[0]; expect(actualCode).toBe(expectedCode, `when linenums=${linenums}`); - expect(actualCode.match(/\r?\n/g)!.length).toBe(5); + expect(actualCode.match(/\r?\n/g)?.length).toBe(5); spy.calls.reset(); }); diff --git a/aio/src/app/custom-elements/elements-loader.ts b/aio/src/app/custom-elements/elements-loader.ts index f06894082b..73b1c10522 100644 --- a/aio/src/app/custom-elements/elements-loader.ts +++ b/aio/src/app/custom-elements/elements-loader.ts @@ -45,12 +45,12 @@ export class ElementsLoader { loadCustomElement(selector: string): Promise { if (this.elementsLoading.has(selector)) { // The custom element is in the process of being loaded and registered. - return this.elementsLoading.get(selector)!; + return this.elementsLoading.get(selector) as Promise; } if (this.elementsToLoad.has(selector)) { // Load and register the custom element (for the first time). - const modulePathLoader = this.elementsToLoad.get(selector)!; + const modulePathLoader = this.elementsToLoad.get(selector) as LoadChildrenCallback; const loadedAndRegistered = (modulePathLoader() as Promise | Type>) .then(elementModuleOrFactory => { @@ -73,7 +73,7 @@ export class ElementsLoader { const CustomElementComponent = elementModuleRef.instance.customElementComponent; const CustomElement = createCustomElement(CustomElementComponent, {injector}); - customElements!.define(selector, CustomElement); + customElements.define(selector, CustomElement); return customElements.whenDefined(selector); }) .then(() => { diff --git a/aio/src/app/custom-elements/toc/toc.component.spec.ts b/aio/src/app/custom-elements/toc/toc.component.spec.ts index 3dc17586cb..6149ab4018 100644 --- a/aio/src/app/custom-elements/toc/toc.component.spec.ts +++ b/aio/src/app/custom-elements/toc/toc.component.spec.ts @@ -337,7 +337,7 @@ describe('TocComponent', () => { it('should re-apply the `active` class when the list elements change', () => { const getActiveTextContent = () => - page.listItems.find(By.css('.active'))!.nativeElement.textContent.trim(); + page.listItems.find(By.css('.active'))?.nativeElement.textContent.trim(); tocComponent.activeIndex = 1; fixture.detectChanges(); diff --git a/aio/src/app/documents/document.service.ts b/aio/src/app/documents/document.service.ts index 83a5da9e33..168e6e71c8 100644 --- a/aio/src/app/documents/document.service.ts +++ b/aio/src/app/documents/document.service.ts @@ -49,7 +49,7 @@ export class DocumentService { if (!this.cache.has(id)) { this.cache.set(id, this.fetchDocument(id)); } - return this.cache.get(id)!; + return this.cache.get(id) as Observable; } private fetchDocument(id: string): Observable { diff --git a/aio/src/app/layout/doc-viewer/doc-viewer.component.spec.ts b/aio/src/app/layout/doc-viewer/doc-viewer.component.spec.ts index 6aabeb6629..ca477216ac 100644 --- a/aio/src/app/layout/doc-viewer/doc-viewer.component.spec.ts +++ b/aio/src/app/layout/doc-viewer/doc-viewer.component.spec.ts @@ -213,10 +213,10 @@ describe('DocViewerComponent', () => { describe('needed', () => { it('should add an embedded ToC element if there is an `

` heading', () => { doPrepareTitleAndToc(DOC_WITH_H1); - const tocEl = getTocEl()!; + const tocEl = getTocEl(); expect(tocEl).toBeTruthy(); - expect(tocEl.classList.contains('embedded')).toBe(true); + expect(tocEl?.classList.contains('embedded')).toBe(true); }); it('should not add a second ToC element if there a hard coded one in place', () => { diff --git a/aio/src/app/layout/doc-viewer/doc-viewer.component.ts b/aio/src/app/layout/doc-viewer/doc-viewer.component.ts index 0fce7f88cd..5a5ed3f4d0 100644 --- a/aio/src/app/layout/doc-viewer/doc-viewer.component.ts +++ b/aio/src/app/layout/doc-viewer/doc-viewer.component.ts @@ -98,9 +98,9 @@ export class DocViewerComponent implements OnDestroy { const needsToc = !!titleEl && !/no-?toc/i.test(titleEl.className); const embeddedToc = targetElem.querySelector('aio-toc.embedded'); - if (needsToc && !embeddedToc) { + if (titleEl && needsToc && !embeddedToc) { // Add an embedded ToC if it's needed and there isn't one in the content already. - titleEl!.insertAdjacentHTML('afterend', ''); + titleEl.insertAdjacentHTML('afterend', ''); } else if (!needsToc && embeddedToc && embeddedToc.parentNode !== null) { // Remove the embedded Toc if it's there and not needed. // We cannot use ChildNode.remove() because of IE11 @@ -223,7 +223,7 @@ export class DocViewerComponent implements OnDestroy { done$ = done$.pipe( // Remove the current view from the viewer. switchMap(() => animateLeave(this.currViewContainer)), - tap(() => this.currViewContainer.parentElement!.removeChild(this.currViewContainer)), + tap(() => (this.currViewContainer.parentElement as HTMLElement).removeChild(this.currViewContainer)), tap(() => this.docRemoved.emit()), ); } diff --git a/aio/src/app/navigation/navigation.service.spec.ts b/aio/src/app/navigation/navigation.service.spec.ts index 96fc80b95b..373c2f77ad 100644 --- a/aio/src/app/navigation/navigation.service.spec.ts +++ b/aio/src/app/navigation/navigation.service.spec.ts @@ -144,7 +144,7 @@ describe('NavigationService', () => { url: 'b', view: 'SideNav', nodes: [ - sideNavNodes[0].children![0], + sideNavNodes[0].children?.[0] as NavigationNode, sideNavNodes[0] ] } @@ -156,8 +156,8 @@ describe('NavigationService', () => { url: 'd', view: 'SideNav', nodes: [ - sideNavNodes[0].children![0].children![1], - sideNavNodes[0].children![0], + sideNavNodes[0].children?.[0].children?.[1] as NavigationNode, + sideNavNodes[0].children?.[0] as NavigationNode, sideNavNodes[0] ] } @@ -201,8 +201,8 @@ describe('NavigationService', () => { url: 'c', view: 'SideNav', nodes: [ - sideNavNodes[0].children![0].children![0], - sideNavNodes[0].children![0], + sideNavNodes[0].children?.[0].children?.[0] as NavigationNode, + sideNavNodes[0].children?.[0] as NavigationNode, sideNavNodes[0] ] } diff --git a/aio/src/app/navigation/navigation.service.ts b/aio/src/app/navigation/navigation.service.ts index 06162678ff..bf3e08a71b 100644 --- a/aio/src/app/navigation/navigation.service.ts +++ b/aio/src/app/navigation/navigation.service.ts @@ -153,7 +153,7 @@ export class NavigationService { if (!navMap.has(cleanedUrl)) { navMap.set(cleanedUrl, {}); } - const navMapItem = navMap.get(cleanedUrl)!; + const navMapItem = navMap.get(cleanedUrl) as CurrentNodes; navMapItem[view] = { url, view, nodes }; } diff --git a/aio/src/app/shared/attribute-utils.spec.ts b/aio/src/app/shared/attribute-utils.spec.ts index dd0ee2c265..25246a4ea9 100644 --- a/aio/src/app/shared/attribute-utils.spec.ts +++ b/aio/src/app/shared/attribute-utils.spec.ts @@ -8,7 +8,7 @@ describe('Attribute Utilities', () => { beforeEach(() => { const div = document.createElement('div'); div.innerHTML = `
`; - testEl = div.querySelector('div')!; + testEl = div.querySelector('div') as HTMLElement; }); describe('getAttrs', () => { diff --git a/aio/src/app/shared/copier.service.ts b/aio/src/app/shared/copier.service.ts index 4b571de452..1a5c97ccac 100644 --- a/aio/src/app/shared/copier.service.ts +++ b/aio/src/app/shared/copier.service.ts @@ -44,7 +44,7 @@ export class CopierService { * @return The temporary `