Convert files to typescript

The change converts the following files to typescript:

* elements/core/gr-main-header/gr-main-header.ts

Change-Id: I4836d9a65cb00c522f6fdabda26e35b3363ab224
diff --git a/polygerrit-ui/app/constants/constants.ts b/polygerrit-ui/app/constants/constants.ts
index 5a925ff..8e8eaf3 100644
--- a/polygerrit-ui/app/constants/constants.ts
+++ b/polygerrit-ui/app/constants/constants.ts
@@ -341,3 +341,20 @@
   OWNER_REVIEWERS = 'OWNER_REVIEWERS',
   ALL = 'ALL',
 }
+
+/**
+ * The authentication type that is configured on the server.
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#auth-info
+ */
+export enum AuthType {
+  OPENID = 'OPENID',
+  OPENID_SSO = 'OPENID_SSO',
+  OAUTH = 'OAUTH',
+  HTTP = 'HTTP',
+  HTTP_LDAP = 'HTTP_LDAP',
+  CLIENT_SSL_CERT_LDAP = 'CLIENT_SSL_CERT_LDAP',
+  LDAP = 'LDAP',
+  LDAP_BIND = 'LDAP_BIND',
+  CUSTOM_EXTENSION = 'CUSTOM_EXTENSION',
+  DEVELOPMENT_BECOME_ANY_ACCOUNT = 'DEVELOPMENT_BECOME_ANY_ACCOUNT',
+}
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
index 88c4cef..5ad0d92 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
@@ -14,40 +14,65 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator.js';
-import '../../shared/gr-dropdown/gr-dropdown.js';
-import '../../shared/gr-icons/gr-icons.js';
-import '../../shared/gr-js-api-interface/gr-js-api-interface.js';
-import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js';
-import '../gr-account-dropdown/gr-account-dropdown.js';
-import '../gr-smart-search/gr-smart-search.js';
-import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js';
-import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
-import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-import {htmlTemplate} from './gr-main-header_html.js';
-import {getBaseUrl, getDocsBaseUrl} from '../../../utils/url-util.js';
-import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
-import {getAdminLinks} from '../../../utils/admin-nav-util.js';
+import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
+import '../../shared/gr-dropdown/gr-dropdown';
+import '../../shared/gr-icons/gr-icons';
+import '../../shared/gr-js-api-interface/gr-js-api-interface';
+import '../../shared/gr-rest-api-interface/gr-rest-api-interface';
+import '../gr-account-dropdown/gr-account-dropdown';
+import '../gr-smart-search/gr-smart-search';
+import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
+import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
+import {PolymerElement} from '@polymer/polymer/polymer-element';
+import {htmlTemplate} from './gr-main-header_html';
+import {getBaseUrl, getDocsBaseUrl} from '../../../utils/url-util';
+import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
+import {getAdminLinks, NavLink} from '../../../utils/admin-nav-util';
+import {customElement, property, observe} from '@polymer/decorators';
+import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {
+  AccountDetailInfo,
+  ServerInfo,
+  TopMenuEntryInfo,
+  TopMenuItemInfo,
+} from '../../../types/common';
+import {JsApiService} from '../../shared/gr-js-api-interface/gr-js-api-types';
+import {AuthType} from '../../../constants/constants';
 
-const DEFAULT_LINKS = [{
-  title: 'Changes',
-  links: [
-    {
-      url: '/q/status:open+-is:wip',
-      name: 'Open',
-    },
-    {
-      url: '/q/status:merged',
-      name: 'Merged',
-    },
-    {
-      url: '/q/status:abandoned',
-      name: 'Abandoned',
-    },
-  ],
-}];
+interface FixedTopMenuItemInfo extends Omit<TopMenuItemInfo, 'target'> {
+  target?: never;
+}
+interface MainHeaderLink {
+  url: string;
+  name: string;
+}
+interface MainHeaderLinkGroup {
+  title: string;
+  links: MainHeaderLink[];
+  class?: string;
+}
 
-const DOCUMENTATION_LINKS = [
+const DEFAULT_LINKS: MainHeaderLinkGroup[] = [
+  {
+    title: 'Changes',
+    links: [
+      {
+        url: '/q/status:open+-is:wip',
+        name: 'Open',
+      },
+      {
+        url: '/q/status:merged',
+        name: 'Merged',
+      },
+      {
+        url: '/q/status:abandoned',
+        name: 'Abandoned',
+      },
+    ],
+  },
+];
+
+const DOCUMENTATION_LINKS: MainHeaderLink[] = [
   {
     url: '/index.html',
     name: 'Table of Contents',
@@ -75,90 +100,68 @@
 ];
 
 // Set of authentication methods that can provide custom registration page.
-const AUTH_TYPES_WITH_REGISTER_URL = new Set([
-  'LDAP',
-  'LDAP_BIND',
-  'CUSTOM_EXTENSION',
+const AUTH_TYPES_WITH_REGISTER_URL: Set<AuthType> = new Set([
+  AuthType.LDAP,
+  AuthType.LDAP_BIND,
+  AuthType.CUSTOM_EXTENSION,
 ]);
 
-/**
- * @extends PolymerElement
- */
-class GrMainHeader extends GestureEventListeners(
-    LegacyElementMixin(
-        PolymerElement)) {
-  static get template() { return htmlTemplate; }
+export interface GrMainHeader {
+  $: {
+    restAPI: RestApiService & Element;
+    jsAPI: JsApiService & Element;
+  };
+}
 
-  static get is() { return 'gr-main-header'; }
-
-  static get properties() {
-    return {
-      searchQuery: {
-        type: String,
-        notify: true,
-      },
-      loggedIn: {
-        type: Boolean,
-        reflectToAttribute: true,
-      },
-      loading: {
-        type: Boolean,
-        reflectToAttribute: true,
-      },
-
-      /** @type {?Object} */
-      _account: Object,
-      _adminLinks: {
-        type: Array,
-        value() { return []; },
-      },
-      _defaultLinks: {
-        type: Array,
-        value() {
-          return DEFAULT_LINKS;
-        },
-      },
-      _docBaseUrl: {
-        type: String,
-        value: null,
-      },
-      _links: {
-        type: Array,
-        computed: '_computeLinks(_defaultLinks, _userLinks, _adminLinks, ' +
-          '_topMenus, _docBaseUrl)',
-      },
-      loginUrl: {
-        type: String,
-        value: '/login',
-      },
-      _userLinks: {
-        type: Array,
-        value() { return []; },
-      },
-      _topMenus: {
-        type: Array,
-        value() { return []; },
-      },
-      _registerText: {
-        type: String,
-        value: 'Sign up',
-      },
-      _registerURL: {
-        type: String,
-        value: null,
-      },
-      mobileSearchHidden: {
-        type: Boolean,
-        value: false,
-      },
-    };
+@customElement('gr-main-header')
+export class GrMainHeader extends GestureEventListeners(
+  LegacyElementMixin(PolymerElement)
+) {
+  static get template() {
+    return htmlTemplate;
   }
 
-  static get observers() {
-    return [
-      '_accountLoaded(_account)',
-    ];
-  }
+  @property({type: String, notify: true})
+  searchQuery?: string;
+
+  @property({type: Boolean, reflectToAttribute: true})
+  loggedIn?: boolean;
+
+  @property({type: Boolean, reflectToAttribute: true})
+  loading?: boolean;
+
+  @property({type: Object})
+  _account?: AccountDetailInfo;
+
+  @property({type: Array})
+  _adminLinks: NavLink[] = [];
+
+  @property({type: String})
+  _docBaseUrl: string | null = null;
+
+  @property({
+    type: Array,
+    computed: '_computeLinks(_userLinks, _adminLinks, _topMenus, _docBaseUrl)',
+  })
+  _links?: MainHeaderLinkGroup[];
+
+  @property({type: String})
+  loginUrl = '/login';
+
+  @property({type: Array})
+  _userLinks: FixedTopMenuItemInfo[] = [];
+
+  @property({type: Array})
+  _topMenus?: TopMenuEntryInfo[] = [];
+
+  @property({type: String})
+  _registerText = 'Sign up';
+
+  @property({type: String})
+  _registerURL?: string;
+
+  @property({type: Boolean})
+  mobileSearchHidden = false;
 
   /** @override */
   ready() {
@@ -182,23 +185,29 @@
     this._loadAccount();
   }
 
-  _computeRelativeURL(path) {
+  _computeRelativeURL(path: string) {
     return '//' + window.location.host + getBaseUrl() + path;
   }
 
-  _computeLinks(defaultLinks, userLinks, adminLinks, topMenus, docBaseUrl) {
+  _computeLinks(
+    userLinks?: FixedTopMenuItemInfo[],
+    adminLinks?: NavLink[],
+    topMenus?: TopMenuEntryInfo[],
+    docBaseUrl?: string | null,
+    // defaultLinks parameter is used in tests only
+    defaultLinks = DEFAULT_LINKS
+  ) {
     // Polymer 2: check for undefined
-    if ([
-      defaultLinks,
-      userLinks,
-      adminLinks,
-      topMenus,
-      docBaseUrl,
-    ].includes(undefined)) {
+    if (
+      userLinks === undefined ||
+      adminLinks === undefined ||
+      topMenus === undefined ||
+      docBaseUrl === undefined
+    ) {
       return undefined;
     }
 
-    const links = defaultLinks.map(menu => {
+    const links: MainHeaderLinkGroup[] = defaultLinks.map(menu => {
       return {
         title: menu.title,
         links: menu.links.slice(),
@@ -222,15 +231,20 @@
       title: 'Browse',
       links: adminLinks.slice(),
     });
-    const topMenuLinks = [];
-    links.forEach(link => { topMenuLinks[link.title] = link.links; });
+    const topMenuLinks: {[name: string]: MainHeaderLink[]} = {};
+    links.forEach(link => {
+      topMenuLinks[link.title] = link.links;
+    });
     for (const m of topMenus) {
-      const items = m.items.map(this._fixCustomMenuItem).filter(link =>
-        // Ignore GWT project links
-        !link.url.includes('${projectName}')
+      const items = m.items.map(this._fixCustomMenuItem).filter(
+        link =>
+          // Ignore GWT project links
+          !link.url.includes('${projectName}')
       );
       if (m.name in topMenuLinks) {
-        items.forEach(link => { topMenuLinks[m.name].push(link); });
+        items.forEach(link => {
+          topMenuLinks[m.name].push(link);
+        });
       } else {
         links.push({
           title: m.name,
@@ -241,8 +255,8 @@
     return links;
   }
 
-  _getDocLinks(docBaseUrl, docLinks) {
-    if (!docBaseUrl || !docLinks) {
+  _getDocLinks(docBaseUrl: string | null, docLinks: MainHeaderLink[]) {
+    if (!docBaseUrl) {
       return [];
     }
     return docLinks.map(link => {
@@ -260,47 +274,62 @@
 
   _loadAccount() {
     this.loading = true;
-    const promises = [
+
+    return Promise.all([
       this.$.restAPI.getAccount(),
       this.$.restAPI.getTopMenus(),
       getPluginLoader().awaitPluginsLoaded(),
-    ];
-
-    return Promise.all(promises).then(result => {
+    ]).then(result => {
       const account = result[0];
       this._account = account;
       this.loggedIn = !!account;
       this.loading = false;
       this._topMenus = result[1];
 
-      return getAdminLinks(account,
-          params => this.$.restAPI.getAccountCapabilities(params),
-          () => this.$.jsAPI.getAdminMenuLinks())
-          .then(res => {
-            this._adminLinks = res.links;
-          });
+      return getAdminLinks(
+        account,
+        () =>
+          this.$.restAPI.getAccountCapabilities().then(capabilities => {
+            if (!capabilities) {
+              throw new Error('getAccountCapabilities returns undefined');
+            }
+            return capabilities;
+          }),
+        () => this.$.jsAPI.getAdminMenuLinks()
+      ).then(res => {
+        this._adminLinks = res.links;
+      });
     });
   }
 
   _loadConfig() {
-    this.$.restAPI.getConfig()
-        .then(config => {
-          this._retrieveRegisterURL(config);
-          return getDocsBaseUrl(config, this.$.restAPI);
-        })
-        .then(docBaseUrl => { this._docBaseUrl = docBaseUrl; });
+    this.$.restAPI
+      .getConfig()
+      .then(config => {
+        if (!config) {
+          throw new Error('getConfig returned undefined');
+        }
+        this._retrieveRegisterURL(config);
+        return getDocsBaseUrl(config, this.$.restAPI);
+      })
+      .then(docBaseUrl => {
+        this._docBaseUrl = docBaseUrl;
+      });
   }
 
-  _accountLoaded(account) {
-    if (!account) { return; }
+  @observe('_account')
+  _accountLoaded(account?: AccountDetailInfo) {
+    if (!account) {
+      return;
+    }
 
     this.$.restAPI.getPreferences().then(prefs => {
-      this._userLinks = prefs && prefs.my ?
-        prefs.my.map(this._fixCustomMenuItem) : [];
+      this._userLinks =
+        prefs && prefs.my ? prefs.my.map(this._fixCustomMenuItem) : [];
     });
   }
 
-  _retrieveRegisterURL(config) {
+  _retrieveRegisterURL(config: ServerInfo) {
     if (AUTH_TYPES_WITH_REGISTER_URL.has(config.auth.auth_type)) {
       this._registerURL = config.auth.register_url;
       if (config.auth.register_text) {
@@ -309,11 +338,12 @@
     }
   }
 
-  _computeIsInvisible(registerURL) {
+  _computeIsInvisible(registerURL?: string) {
     return registerURL ? '' : 'invisible';
   }
 
-  _fixCustomMenuItem(linkObj) {
+  _fixCustomMenuItem(linkObj: TopMenuItemInfo): FixedTopMenuItemInfo {
+    // TODO(TS): make a copy of linkObj instead of modifying the existing one
     // Normalize all urls to PolyGerrit style.
     if (linkObj.url.startsWith('#')) {
       linkObj.url = linkObj.url.slice(1);
@@ -328,30 +358,29 @@
     // so we'll just disable it altogether for now.
     delete linkObj.target;
 
-    return linkObj;
+    return (linkObj as unknown) as FixedTopMenuItemInfo;
   }
 
   _generateSettingsLink() {
     return getBaseUrl() + '/settings/';
   }
 
-  _onMobileSearchTap(e) {
+  _onMobileSearchTap(e: Event) {
     e.preventDefault();
     e.stopPropagation();
-    this.dispatchEvent(new CustomEvent('mobile-search', {
-      composed: true, bubbles: false,
-    }));
+    this.dispatchEvent(
+      new CustomEvent('mobile-search', {
+        composed: true,
+        bubbles: false,
+      })
+    );
   }
 
-  _computeLinkGroupClass(linkGroup) {
-    if (linkGroup && linkGroup.class) {
-      return linkGroup.class;
-    }
-
-    return '';
+  _computeLinkGroupClass(linkGroup: MainHeaderLinkGroup) {
+    return linkGroup.class ?? '';
   }
 
-  _computeShowHideAriaLabel(mobileSearchHidden) {
+  _computeShowHideAriaLabel(mobileSearchHidden: boolean) {
     if (mobileSearchHidden) {
       return 'Show Searchbar';
     } else {
@@ -360,4 +389,8 @@
   }
 }
 
-customElements.define(GrMainHeader.is, GrMainHeader);
+declare global {
+  interface HTMLElementTagNameMap {
+    'gr-main-header': GrMainHeader;
+  }
+}
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.js b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.js
index 48194a6..e4db65f 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.js
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.js
@@ -103,22 +103,22 @@
 
     // When no admin links are passed, it should use the default.
     assert.deepEqual(element._computeLinks(
-        defaultLinks,
         /* userLinks= */[],
         adminLinks,
         /* topMenus= */[],
-        /* docBaseUrl= */ ''
+        /* docBaseUrl= */ '',
+        defaultLinks
     ),
     defaultLinks.concat({
       title: 'Browse',
       links: adminLinks,
     }));
     assert.deepEqual(element._computeLinks(
-        defaultLinks,
         userLinks,
         adminLinks,
         /* topMenus= */[],
-        /* docBaseUrl= */ ''
+        /* docBaseUrl= */ '',
+        defaultLinks
     ),
     defaultLinks.concat([
       {
@@ -142,7 +142,6 @@
 
     assert.deepEqual(element._getDocLinks(null, docLinks), []);
     assert.deepEqual(element._getDocLinks('', docLinks), []);
-    assert.deepEqual(element._getDocLinks('base', null), []);
     assert.deepEqual(element._getDocLinks('base', []), []);
 
     assert.deepEqual(element._getDocLinks('base', docLinks), [{
@@ -172,11 +171,11 @@
       }],
     }];
     assert.deepEqual(element._computeLinks(
-        /* defaultLinks= */ [],
         /* userLinks= */ [],
         adminLinks,
         topMenus,
-        /* baseDocUrl= */ ''
+        /* baseDocUrl= */ '',
+        /* defaultLinks= */ []
     ), [{
       title: 'Browse',
       links: adminLinks,
@@ -208,11 +207,11 @@
       }],
     }];
     assert.deepEqual(element._computeLinks(
-        /* defaultLinks= */ [],
         /* userLinks= */ [],
         adminLinks,
         topMenus,
-        /* baseDocUrl= */ ''
+        /* baseDocUrl= */ '',
+        /* defaultLinks= */ []
     ), [{
       title: 'Browse',
       links: adminLinks,
@@ -247,11 +246,11 @@
       }],
     }];
     assert.deepEqual(element._computeLinks(
-        /* defaultLinks= */ [],
         /* userLinks= */ [],
         adminLinks,
         topMenus,
-        /* baseDocUrl= */ ''
+        /* baseDocUrl= */ '',
+        /* defaultLinks= */ []
     ), [{
       title: 'Browse',
       links: adminLinks,
@@ -284,11 +283,11 @@
       }],
     }];
     assert.deepEqual(element._computeLinks(
-        defaultLinks,
         /* userLinks= */ [],
         /* adminLinks= */ [],
         topMenus,
-        /* baseDocUrl= */ ''
+        /* baseDocUrl= */ '',
+        defaultLinks
     ), [{
       title: 'Faves',
       links: defaultLinks[0].links.concat([{
@@ -315,11 +314,11 @@
       }],
     }];
     assert.deepEqual(element._computeLinks(
-        /* defaultLinks= */ [],
         userLinks,
         /* adminLinks= */ [],
         topMenus,
-        /* baseDocUrl= */ ''
+        /* baseDocUrl= */ '',
+        /* defaultLinks= */ []
     ), [{
       title: 'Your',
       links: userLinks.concat([{
@@ -346,11 +345,11 @@
       }],
     }];
     assert.deepEqual(element._computeLinks(
-        /* defaultLinks= */ [],
         /* userLinks= */ [],
         adminLinks,
         topMenus,
-        /* baseDocUrl= */ ''
+        /* baseDocUrl= */ '',
+        /* defaultLinks= */ []
     ), [{
       title: 'Browse',
       links: adminLinks.concat([{
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
index 26bf50a..8c26d4a 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
@@ -26,7 +26,7 @@
   RevisionInfo,
 } from '../../../types/common';
 import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
-import {GrAdminApi} from '../../plugins/gr-admin-api/gr-admin-api';
+import {GrAdminApi, MenuLink} from '../../plugins/gr-admin-api/gr-admin-api';
 import {
   JsApiService,
   EventCallback,
@@ -294,8 +294,8 @@
       );
   }
 
-  getAdminMenuLinks() {
-    const links = [];
+  getAdminMenuLinks(): MenuLink[] {
+    const links: MenuLink[] = [];
     for (const cb of this._getEventCallbacks(EventType.ADMIN_MENU_LINKS)) {
       const adminApi = (cb as unknown) as GrAdminApi;
       links.push(...adminApi.getMenuLinks());
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
index 505e62e..261298b 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
@@ -18,6 +18,7 @@
 import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
 import {DiffLayer} from '../../../types/types';
 import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
+import {MenuLink} from '../../plugins/gr-admin-api/gr-admin-api';
 
 export interface ShowChangeDetail {
   change: ChangeInfo;
@@ -50,5 +51,6 @@
   getDiffLayers(path: string, changeNum: number): DiffLayer[];
   disposeDiffLayers(path: string): void;
   getCoverageAnnotationApi(): Promise<GrAnnotationActionsInterface | undefined>;
+  getAdminMenuLinks(): MenuLink[];
   // TODO(TS): Add more methods when needed for the TS conversion.
 }
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
index 70a1ace..15cdac4 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
@@ -138,6 +138,7 @@
   RevisionId,
   GroupName,
   Hashtag,
+  TopMenuEntryInfo,
 } from '../../../types/common';
 import {
   CancelConditionCallback,
@@ -3221,12 +3222,12 @@
     }) as Promise<CapabilityInfoMap | undefined>;
   }
 
-  getTopMenus(errFn?: ErrorCallback) {
+  getTopMenus(errFn?: ErrorCallback): Promise<TopMenuEntryInfo[] | undefined> {
     return this._fetchSharedCacheURL({
       url: '/config/server/top-menus',
       errFn,
       reportUrlAsIs: true,
-    });
+    }) as Promise<TopMenuEntryInfo[] | undefined>;
   }
 
   setAssignee(
diff --git a/polygerrit-ui/app/services/services/gr-rest-api/gr-rest-api.ts b/polygerrit-ui/app/services/services/gr-rest-api/gr-rest-api.ts
index bf8b25a..6b93082 100644
--- a/polygerrit-ui/app/services/services/gr-rest-api/gr-rest-api.ts
+++ b/polygerrit-ui/app/services/services/gr-rest-api/gr-rest-api.ts
@@ -97,6 +97,7 @@
   HashtagsInput,
   Hashtag,
   FileNameToFileInfoMap,
+  TopMenuEntryInfo,
 } from '../../../types/common';
 import {ParsedChangeInfo} from '../../../elements/shared/gr-rest-api-interface/gr-reviewer-updates-parser';
 import {HttpMethod, IgnoreWhitespaceType} from '../../../constants/constants';
@@ -841,4 +842,6 @@
     reviewed: boolean,
     errFn: ErrorCallback
   ): Promise<Response | undefined>;
+
+  getTopMenus(errFn?: ErrorCallback): Promise<TopMenuEntryInfo[] | undefined>;
 }
diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts
index 15d630f..dca8115 100644
--- a/polygerrit-ui/app/types/common.ts
+++ b/polygerrit-ui/app/types/common.ts
@@ -43,6 +43,7 @@
   DraftsAction,
   NotifyType,
   EmailFormat,
+  AuthType,
 } from '../constants/constants';
 import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
 
@@ -740,10 +741,10 @@
 /**
  * The AuthInfo entity contains information about the authentication
  * configuration of the Gerrit server.
- * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#auth-info
  */
 export interface AuthInfo {
-  type: string;
+  auth_type: AuthType; // docs incorrectly names it 'type'
   use_contributor_agreements: boolean;
   contributor_agreements?: ContributorAgreementInfo;
   editable_account_fields: string;
@@ -1121,17 +1122,17 @@
 
 /**
  * The TopMenuEntryInfo entity contains information about a top menu entry.
- * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#top-menu-entry-info
  */
 export interface TopMenuEntryInfo {
   name: string;
-  items: string;
+  items: TopMenuItemInfo[];
 }
 
 /**
  * The TopMenuItemInfo entity contains information about a menu item ina top
  * menu entry.
- * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#top-menu-item-info
  */
 export interface TopMenuItemInfo {
   url: string;