[JSDOC2TS]: Migrate main

Bug: chromium:1158760
Change-Id: Ibe9b0fe480794bb788253a3b9902d4cc42a5ca2e
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2789347
Commit-Queue: Jan Scheffler <[email protected]>
Reviewed-by: Tim van der Lippe <[email protected]>
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index b142c6d..6f5b44b 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -137,7 +137,7 @@
 def _CheckExperimentTelemetry(input_api, output_api):
     experiment_telemetry_files = [
         input_api.os_path.join(input_api.PresubmitLocalPath(), 'front_end',
-                               'main', 'MainImpl.js'),
+                               'main', 'MainImpl.ts'),
         input_api.os_path.join(input_api.PresubmitLocalPath(), 'front_end',
                                'core', 'host', 'UserMetrics.ts')
     ]
diff --git a/front_end/core/i18n/locales/en-US.json b/front_end/core/i18n/locales/en-US.json
index a42258e..237a6d2 100644
--- a/front_end/core/i18n/locales/en-US.json
+++ b/front_end/core/i18n/locales/en-US.json
@@ -1973,43 +1973,43 @@
   "main/main-meta.ts | zoomOut": {
     "message": "Zoom out"
   },
-  "main/MainImpl.js | customizeAndControlDevtools": {
+  "main/MainImpl.ts | customizeAndControlDevtools": {
     "message": "Customize and control DevTools"
   },
-  "main/MainImpl.js | dockSide": {
+  "main/MainImpl.ts | dockSide": {
     "message": "Dock side"
   },
-  "main/MainImpl.js | dockToBottom": {
+  "main/MainImpl.ts | dockToBottom": {
     "message": "Dock to bottom"
   },
-  "main/MainImpl.js | dockToLeft": {
+  "main/MainImpl.ts | dockToLeft": {
     "message": "Dock to left"
   },
-  "main/MainImpl.js | dockToRight": {
+  "main/MainImpl.ts | dockToRight": {
     "message": "Dock to right"
   },
-  "main/MainImpl.js | focusDebuggee": {
+  "main/MainImpl.ts | focusDebuggee": {
     "message": "Focus debuggee"
   },
-  "main/MainImpl.js | help": {
+  "main/MainImpl.ts | help": {
     "message": "Help"
   },
-  "main/MainImpl.js | hideConsoleDrawer": {
+  "main/MainImpl.ts | hideConsoleDrawer": {
     "message": "Hide console drawer"
   },
-  "main/MainImpl.js | moreTools": {
+  "main/MainImpl.ts | moreTools": {
     "message": "More tools"
   },
-  "main/MainImpl.js | placementOfDevtoolsRelativeToThe": {
+  "main/MainImpl.ts | placementOfDevtoolsRelativeToThe": {
     "message": "Placement of DevTools relative to the page. ({PH1} to restore last position)"
   },
-  "main/MainImpl.js | showConsoleDrawer": {
+  "main/MainImpl.ts | showConsoleDrawer": {
     "message": "Show console drawer"
   },
-  "main/MainImpl.js | theSystempreferredColorSchemeHas": {
+  "main/MainImpl.ts | theSystempreferredColorSchemeHas": {
     "message": "The system-preferred color scheme has changed. To apply this change to DevTools, reload."
   },
-  "main/MainImpl.js | undockIntoSeparateWindow": {
+  "main/MainImpl.ts | undockIntoSeparateWindow": {
     "message": "Undock into separate window"
   },
   "node_debugger/node_debugger-meta.ts | node": {
diff --git a/front_end/core/i18n/locales/en-XL.json b/front_end/core/i18n/locales/en-XL.json
index 689ca0b..e83bd41 100644
--- a/front_end/core/i18n/locales/en-XL.json
+++ b/front_end/core/i18n/locales/en-XL.json
@@ -1973,43 +1973,43 @@
   "main/main-meta.ts | zoomOut": {
     "message": "Ẑóôḿ ôút̂"
   },
-  "main/MainImpl.js | customizeAndControlDevtools": {
+  "main/MainImpl.ts | customizeAndControlDevtools": {
     "message": "Ĉúŝt́ôḿîźê án̂d́ ĉón̂t́r̂ól̂ D́êv́T̂óôĺŝ"
   },
-  "main/MainImpl.js | dockSide": {
+  "main/MainImpl.ts | dockSide": {
     "message": "D̂óĉḱ ŝíd̂é"
   },
-  "main/MainImpl.js | dockToBottom": {
+  "main/MainImpl.ts | dockToBottom": {
     "message": "D̂óĉḱ t̂ó b̂ót̂t́ôḿ"
   },
-  "main/MainImpl.js | dockToLeft": {
+  "main/MainImpl.ts | dockToLeft": {
     "message": "D̂óĉḱ t̂ó l̂éf̂t́"
   },
-  "main/MainImpl.js | dockToRight": {
+  "main/MainImpl.ts | dockToRight": {
     "message": "D̂óĉḱ t̂ó r̂íĝh́t̂"
   },
-  "main/MainImpl.js | focusDebuggee": {
+  "main/MainImpl.ts | focusDebuggee": {
     "message": "F̂óĉúŝ d́êb́ûǵĝéê"
   },
-  "main/MainImpl.js | help": {
+  "main/MainImpl.ts | help": {
     "message": "Ĥél̂ṕ"
   },
-  "main/MainImpl.js | hideConsoleDrawer": {
+  "main/MainImpl.ts | hideConsoleDrawer": {
     "message": "Ĥíd̂é ĉón̂śôĺê d́r̂áŵér̂"
   },
-  "main/MainImpl.js | moreTools": {
+  "main/MainImpl.ts | moreTools": {
     "message": "M̂ór̂é t̂óôĺŝ"
   },
-  "main/MainImpl.js | placementOfDevtoolsRelativeToThe": {
+  "main/MainImpl.ts | placementOfDevtoolsRelativeToThe": {
     "message": "P̂ĺâćêḿêńt̂ óf̂ D́êv́T̂óôĺŝ ŕêĺât́îv́ê t́ô t́ĥé p̂áĝé. ({PH1} t̂ó r̂éŝt́ôŕê ĺâśt̂ ṕôśît́îón̂)"
   },
-  "main/MainImpl.js | showConsoleDrawer": {
+  "main/MainImpl.ts | showConsoleDrawer": {
     "message": "Ŝh́ôẃ ĉón̂śôĺê d́r̂áŵér̂"
   },
-  "main/MainImpl.js | theSystempreferredColorSchemeHas": {
+  "main/MainImpl.ts | theSystempreferredColorSchemeHas": {
     "message": "T̂h́ê śŷśt̂ém̂-ṕr̂éf̂ér̂ŕêd́ ĉól̂ór̂ śĉh́êḿê h́âś ĉh́âńĝéd̂. T́ô áp̂ṕl̂ý t̂h́îś ĉh́âńĝé t̂ó D̂év̂T́ôól̂ś, r̂él̂óâd́."
   },
-  "main/MainImpl.js | undockIntoSeparateWindow": {
+  "main/MainImpl.ts | undockIntoSeparateWindow": {
     "message": "Ûńd̂óĉḱ îńt̂ó ŝép̂ár̂át̂é ŵín̂d́ôẃ"
   },
   "node_debugger/node_debugger-meta.ts | node": {
diff --git a/front_end/main/BUILD.gn b/front_end/main/BUILD.gn
index 7a4feb5..462a764 100644
--- a/front_end/main/BUILD.gn
+++ b/front_end/main/BUILD.gn
@@ -7,9 +7,9 @@
 
 devtools_module("main") {
   sources = [
-    "ExecutionContextSelector.js",
-    "MainImpl.js",
-    "SimpleApp.js",
+    "ExecutionContextSelector.ts",
+    "MainImpl.ts",
+    "SimpleApp.ts",
   ]
 
   deps = [
@@ -39,7 +39,7 @@
 }
 
 devtools_entrypoint("legacy") {
-  entrypoint = "main-legacy.js"
+  entrypoint = "main-legacy.ts"
 
   deps = [ ":bundle" ]
 }
diff --git a/front_end/main/ExecutionContextSelector.js b/front_end/main/ExecutionContextSelector.ts
similarity index 71%
rename from front_end/main/ExecutionContextSelector.js
rename to front_end/main/ExecutionContextSelector.ts
index 3150ba6..fde97a7 100644
--- a/front_end/main/ExecutionContextSelector.js
+++ b/front_end/main/ExecutionContextSelector.ts
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/* eslint-disable rulesdir/no_underscored_properties */
+
 import * as Common from '../common/common.js';  // eslint-disable-line no-unused-vars
 import * as SDK from '../core/sdk/sdk.js';
 import * as UI from '../ui/ui.js';  // eslint-disable-line no-unused-vars
 
-/**
- * @implements {SDK.SDKModel.SDKModelObserver<!SDK.RuntimeModel.RuntimeModel>}
- */
-export class ExecutionContextSelector {
-  /**
-   * @param {!SDK.SDKModel.TargetManager} targetManager
-   * @param {!UI.Context.Context} context
-   */
-  constructor(targetManager, context) {
+export class ExecutionContextSelector implements SDK.SDKModel.SDKModelObserver<SDK.RuntimeModel.RuntimeModel> {
+  _targetManager: SDK.SDKModel.TargetManager;
+  _context: UI.Context.Context;
+  _lastSelectedContextId?: string;
+  _ignoreContextChanged?: boolean;
+
+  constructor(targetManager: SDK.SDKModel.TargetManager, context: UI.Context.Context) {
     context.addFlavorChangeListener(SDK.RuntimeModel.ExecutionContext, this._executionContextChanged, this);
     context.addFlavorChangeListener(SDK.SDKModel.Target, this._targetChanged, this);
 
@@ -32,19 +32,12 @@
     targetManager.observeModels(SDK.RuntimeModel.RuntimeModel, this);
   }
 
-  /**
-   * @override
-   * @param {!SDK.RuntimeModel.RuntimeModel} runtimeModel
-   */
-  modelAdded(runtimeModel) {
+  modelAdded(runtimeModel: SDK.RuntimeModel.RuntimeModel): void {
     // Defer selecting default target since we need all clients to get their
     // targetAdded notifications first.
     queueMicrotask(deferred.bind(this));
 
-    /**
-     * @this {ExecutionContextSelector}
-     */
-    function deferred() {
+    function deferred(this: ExecutionContextSelector): void {
       // We always want the second context for the service worker targets.
       if (!this._context.flavor(SDK.SDKModel.Target)) {
         this._context.setFlavor(SDK.SDKModel.Target, runtimeModel.target());
@@ -52,11 +45,7 @@
     }
   }
 
-  /**
-   * @override
-   * @param {!SDK.RuntimeModel.RuntimeModel} runtimeModel
-   */
-  modelRemoved(runtimeModel) {
+  modelRemoved(runtimeModel: SDK.RuntimeModel.RuntimeModel): void {
     const currentExecutionContext = this._context.flavor(SDK.RuntimeModel.ExecutionContext);
     if (currentExecutionContext && currentExecutionContext.runtimeModel === runtimeModel) {
       this._currentExecutionContextGone();
@@ -68,11 +57,8 @@
     }
   }
 
-  /**
-   * @param {!Common.EventTarget.EventTargetEvent} event
-   */
-  _executionContextChanged(event) {
-    const newContext = /** @type {?SDK.RuntimeModel.ExecutionContext} */ (event.data);
+  _executionContextChanged(event: Common.EventTarget.EventTargetEvent): void {
+    const newContext = (event.data as SDK.RuntimeModel.ExecutionContext | null);
     if (newContext) {
       this._context.setFlavor(SDK.SDKModel.Target, newContext.target());
       if (!this._ignoreContextChanged) {
@@ -81,19 +67,12 @@
     }
   }
 
-  /**
-   * @param {!SDK.RuntimeModel.ExecutionContext} executionContext
-   * @return {string}
-   */
-  _contextPersistentId(executionContext) {
+  _contextPersistentId(executionContext: SDK.RuntimeModel.ExecutionContext): string {
     return executionContext.isDefault ? executionContext.target().name() + ':' + executionContext.frameId : '';
   }
 
-  /**
-   * @param {!Common.EventTarget.EventTargetEvent} event
-   */
-  _targetChanged(event) {
-    const newTarget = /** @type {?SDK.SDKModel.Target} */ (event.data);
+  _targetChanged(event: Common.EventTarget.EventTargetEvent): void {
+    const newTarget = (event.data as SDK.SDKModel.Target | null);
     const currentContext = this._context.flavor(SDK.RuntimeModel.ExecutionContext);
 
     if (!newTarget || (currentContext && currentContext.target() === newTarget)) {
@@ -106,7 +85,7 @@
       return;
     }
 
-    let newContext = null;
+    let newContext: SDK.RuntimeModel.ExecutionContext|null = null;
     for (let i = 0; i < executionContexts.length && !newContext; ++i) {
       if (this._shouldSwitchToContext(executionContexts[i])) {
         newContext = executionContexts[i];
@@ -122,11 +101,7 @@
     this._ignoreContextChanged = false;
   }
 
-  /**
-   * @param {!SDK.RuntimeModel.ExecutionContext} executionContext
-   * @return {boolean}
-   */
-  _shouldSwitchToContext(executionContext) {
+  _shouldSwitchToContext(executionContext: SDK.RuntimeModel.ExecutionContext): boolean {
     if (this._lastSelectedContextId && this._lastSelectedContextId === this._contextPersistentId(executionContext)) {
       return true;
     }
@@ -136,11 +111,7 @@
     return false;
   }
 
-  /**
-   * @param {!SDK.RuntimeModel.ExecutionContext} executionContext
-   * @return {boolean}
-   */
-  _isDefaultContext(executionContext) {
+  _isDefaultContext(executionContext: SDK.RuntimeModel.ExecutionContext): boolean {
     if (!executionContext.isDefault || !executionContext.frameId) {
       return false;
     }
@@ -155,28 +126,19 @@
     return false;
   }
 
-  /**
-   * @param {!Common.EventTarget.EventTargetEvent} event
-   */
-  _onExecutionContextCreated(event) {
-    this._switchContextIfNecessary(/** @type {!SDK.RuntimeModel.ExecutionContext} */ (event.data));
+  _onExecutionContextCreated(event: Common.EventTarget.EventTargetEvent): void {
+    this._switchContextIfNecessary((event.data as SDK.RuntimeModel.ExecutionContext));
   }
 
-  /**
-   * @param {!Common.EventTarget.EventTargetEvent} event
-   */
-  _onExecutionContextDestroyed(event) {
-    const executionContext = /** @type {!SDK.RuntimeModel.ExecutionContext}*/ (event.data);
+  _onExecutionContextDestroyed(event: Common.EventTarget.EventTargetEvent): void {
+    const executionContext = (event.data as SDK.RuntimeModel.ExecutionContext);
     if (this._context.flavor(SDK.RuntimeModel.ExecutionContext) === executionContext) {
       this._currentExecutionContextGone();
     }
   }
 
-  /**
-   * @param {!Common.EventTarget.EventTargetEvent} event
-   */
-  _onExecutionContextOrderChanged(event) {
-    const runtimeModel = /** @type {!SDK.RuntimeModel.RuntimeModel} */ (event.data);
+  _onExecutionContextOrderChanged(event: Common.EventTarget.EventTargetEvent): void {
+    const runtimeModel = (event.data as SDK.RuntimeModel.RuntimeModel);
     const executionContexts = runtimeModel.executionContexts();
     for (let i = 0; i < executionContexts.length; i++) {
       if (this._switchContextIfNecessary(executionContexts[i])) {
@@ -185,11 +147,7 @@
     }
   }
 
-  /**
-   * @param {!SDK.RuntimeModel.ExecutionContext} executionContext
-   * @return {boolean}
-   */
-  _switchContextIfNecessary(executionContext) {
+  _switchContextIfNecessary(executionContext: SDK.RuntimeModel.ExecutionContext): boolean {
     if (!this._context.flavor(SDK.RuntimeModel.ExecutionContext) || this._shouldSwitchToContext(executionContext)) {
       this._ignoreContextChanged = true;
       this._context.setFlavor(SDK.RuntimeModel.ExecutionContext, executionContext);
@@ -199,9 +157,9 @@
     return false;
   }
 
-  _currentExecutionContextGone() {
+  _currentExecutionContextGone(): void {
     const runtimeModels = this._targetManager.models(SDK.RuntimeModel.RuntimeModel);
-    let newContext = null;
+    let newContext: SDK.RuntimeModel.ExecutionContext|null = null;
     for (let i = 0; i < runtimeModels.length && !newContext; ++i) {
       const executionContexts = runtimeModels[i].executionContexts();
       for (const executionContext of executionContexts) {
diff --git a/front_end/main/MainImpl.js b/front_end/main/MainImpl.ts
similarity index 85%
rename from front_end/main/MainImpl.js
rename to front_end/main/MainImpl.ts
index 03d62b7..78564d1 100644
--- a/front_end/main/MainImpl.js
+++ b/front_end/main/MainImpl.ts
@@ -1,3 +1,7 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
 /*
  * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
  * Copyright (C) 2007 Matt Lilek ([email protected]).
@@ -28,6 +32,8 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/* eslint-disable rulesdir/no_underscored_properties */
+
 import * as Bindings from '../bindings/bindings.js';
 import * as Common from '../common/common.js';
 import * as Components from '../components/components.js';
@@ -105,44 +111,37 @@
   */
   help: 'Help',
 };
-const str_ = i18n.i18n.registerUIStrings('main/MainImpl.js', UIStrings);
+const str_ = i18n.i18n.registerUIStrings('main/MainImpl.ts', UIStrings);
 const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
 export class MainImpl {
+  _lateInitDonePromise!: Promise<void>;
+
   constructor() {
     MainImpl._instanceForTest = this;
     Platform.runOnWindowLoad(() => {
       this._loaded();
     });
-
-    /** @type {!Promise<void>} */
-    this._lateInitDonePromise;
   }
 
-  /**
-   * @param {string} label
-   */
-  static time(label) {
+  static time(label: string): void {
     if (Host.InspectorFrontendHost.isUnderTest()) {
       return;
     }
     console.time(label);
   }
 
-  /**
-   * @param {string} label
-   */
-  static timeEnd(label) {
+  static timeEnd(label: string): void {
     if (Host.InspectorFrontendHost.isUnderTest()) {
       return;
     }
     console.timeEnd(label);
   }
 
-  async _loaded() {
+  async _loaded(): Promise<void> {
     console.timeStamp('Main._loaded');
     await Root.Runtime.appStarted;
     Root.Runtime.Runtime.setPlatform(Host.Platform.platform());
-    const prefs = await new Promise(resolve => {
+    const prefs = await new Promise<{[key: string]: string}>(resolve => {
       Host.InspectorFrontendHost.InspectorFrontendHostInstance.getPreferences(resolve);
     });
 
@@ -152,7 +151,7 @@
     this._createAppUI();
   }
 
-  async requestAndRegisterLocaleData() {
+  async requestAndRegisterLocaleData(): Promise<void> {
     const hostLocale = navigator.language || 'en-US';
     i18n.i18n.registerLocale(hostLocale);
     const locale = i18n.i18n.registeredLocale;
@@ -166,11 +165,9 @@
     }
   }
 
-  /**
-   * @param {!Object<string, string>} prefs
-   * Note: this function is called from testSettings in Tests.js.
-   */
-  _createSettings(prefs) {
+  _createSettings(prefs: {
+    [x: string]: string,
+  }): void {
     this._initializeExperiments();
     let storagePrefix = '';
     if (Host.Platform.isCustomDevtoolsFrontend()) {
@@ -202,7 +199,7 @@
     }
   }
 
-  _initializeExperiments() {
+  _initializeExperiments(): void {
     Root.Runtime.experiments.register('applyCustomStylesheet', 'Allow custom UI themes');
     Root.Runtime.experiments.register('captureNodeCreationStacks', 'Capture node creation stacks');
     Root.Runtime.experiments.register('sourcesPrettyPrint', 'Automatically pretty print in the Sources Panel');
@@ -300,7 +297,7 @@
       Host.userMetrics.experimentEnabledAtLaunch(experiment.name);
     }
   }
-  async _createAppUI() {
+  async _createAppUI(): Promise<void> {
     MainImpl.time('Main._createAppUI');
 
     // @ts-ignore layout test global
@@ -321,8 +318,7 @@
             i18nString(UIStrings.theSystempreferredColorSchemeHas));
       });
     }
-
-    UI.UIUtils.installComponentRootStyles(/** @type {!Element} */ (document.body));
+    UI.UIUtils.installComponentRootStyles((document.body as Element));
 
     this._addMainEventListeners(document);
 
@@ -363,27 +359,27 @@
     self.Bindings.resourceMapping = Bindings.ResourceMapping.ResourceMapping.instance({
       forceNew: true,
       targetManager: SDK.SDKModel.TargetManager.instance(),
-      workspace: Workspace.Workspace.WorkspaceImpl.instance()
+      workspace: Workspace.Workspace.WorkspaceImpl.instance(),
     });
     new Bindings.PresentationConsoleMessageHelper.PresentationConsoleMessageManager();
     // @ts-ignore layout test global
     self.Bindings.cssWorkspaceBinding = Bindings.CSSWorkspaceBinding.CSSWorkspaceBinding.instance({
       forceNew: true,
       targetManager: SDK.SDKModel.TargetManager.instance(),
-      workspace: Workspace.Workspace.WorkspaceImpl.instance()
+      workspace: Workspace.Workspace.WorkspaceImpl.instance(),
     });
     // @ts-ignore layout test global
     self.Bindings.debuggerWorkspaceBinding = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance({
       forceNew: true,
       targetManager: SDK.SDKModel.TargetManager.instance(),
-      workspace: Workspace.Workspace.WorkspaceImpl.instance()
+      workspace: Workspace.Workspace.WorkspaceImpl.instance(),
     });
     // @ts-ignore layout test global
     self.Bindings.breakpointManager = Bindings.BreakpointManager.BreakpointManager.instance({
       forceNew: true,
       workspace: Workspace.Workspace.WorkspaceImpl.instance(),
       targetManager: SDK.SDKModel.TargetManager.instance(),
-      debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
+      debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance(),
     });
     // @ts-ignore layout test global
     self.Extensions.extensionServer = Extensions.ExtensionServer.ExtensionServer.instance({forceNew: true});
@@ -405,7 +401,7 @@
     self.Persistence.persistence = Persistence.Persistence.PersistenceImpl.instance({
       forceNew: true,
       workspace: Workspace.Workspace.WorkspaceImpl.instance(),
-      breakpointManager: Bindings.BreakpointManager.BreakpointManager.instance()
+      breakpointManager: Bindings.BreakpointManager.BreakpointManager.instance(),
     });
     // @ts-ignore layout test global
     self.Persistence.networkPersistenceManager =
@@ -416,7 +412,7 @@
     // @ts-ignore layout test global
     self.Bindings.ignoreListManager = Bindings.IgnoreListManager.IgnoreListManager.instance({
       forceNew: true,
-      debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
+      debuggerWorkspaceBinding: Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance(),
     });
 
     new PauseListener();
@@ -439,12 +435,9 @@
     await this._showAppUI(await appProvider.loadAppProvider());
   }
 
-  /**
-   * @param {!Object} appProvider
-   */
-  async _showAppUI(appProvider) {
+  async _showAppUI(appProvider: Object): Promise<void> {
     MainImpl.time('Main._showAppUI');
-    const app = /** @type {!Common.AppProvider.AppProvider} */ (appProvider).createApp();
+    const app = (appProvider as Common.AppProvider.AppProvider).createApp();
     // It is important to kick controller lifetime after apps are instantiated.
     UI.DockController.DockController.instance().initialize();
     app.presentUI(document);
@@ -473,7 +466,7 @@
     MainImpl.timeEnd('Main._showAppUI');
   }
 
-  async _initializeTarget() {
+  async _initializeTarget(): Promise<void> {
     MainImpl.time('Main._initializeTarget');
 
     // We rely on having the early initialization runnables registered in Common when an app loads its
@@ -489,20 +482,17 @@
     MainImpl.timeEnd('Main._initializeTarget');
   }
 
-  _lateInitialization() {
+  _lateInitialization(): void {
     MainImpl.time('Main._lateInitialization');
     Extensions.ExtensionServer.ExtensionServer.instance().initializeExtensions();
-    /** @type {!Array<!Promise<void>>} */
-    const promises = Common.Runnable.lateInitializationRunnables().map(runnableInstance => runnableInstance().run());
+    const promises: Promise<void>[] =
+        Common.Runnable.lateInitializationRunnables().map(runnableInstance => runnableInstance().run());
     if (Root.Runtime.experiments.isEnabled('liveHeapProfile')) {
       const setting = 'memoryLiveHeapProfile';
       if (Common.Settings.Settings.instance().moduleSetting(setting).get()) {
         promises.push(PerfUI.LiveHeapProfile.LiveHeapProfile.instance().run());
       } else {
-        /**
-         * @param {!Common.EventTarget.EventTargetEvent} event
-         */
-        const changeListener = async event => {
+        const changeListener = async(event: Common.EventTarget.EventTargetEvent): Promise<void> => {
           if (!event.data) {
             return;
           }
@@ -516,34 +506,25 @@
     MainImpl.timeEnd('Main._lateInitialization');
   }
 
-  /**
-   * @return {?Promise<void>}
-   */
-  lateInitDonePromiseForTest() {
+  lateInitDonePromiseForTest(): Promise<void>|null {
     return this._lateInitDonePromise;
   }
 
-  _registerMessageSinkListener() {
+  _registerMessageSinkListener(): void {
     Common.Console.Console.instance().addEventListener(Common.Console.Events.MessageAdded, messageAdded);
 
-    /**
-     * @param {!Common.EventTarget.EventTargetEvent} event
-     */
-    function messageAdded(event) {
-      const message = /** @type {!Common.Console.Message} */ (event.data);
+    function messageAdded(event: Common.EventTarget.EventTargetEvent): void {
+      const message = (event.data as Common.Console.Message);
       if (message.show) {
         Common.Console.Console.instance().show();
       }
     }
   }
 
-  /**
-   * @param {!Common.EventTarget.EventTargetEvent} event
-   */
-  _revealSourceLine(event) {
-    const url = /** @type {string} */ (event.data['url']);
-    const lineNumber = /** @type {number} */ (event.data['lineNumber']);
-    const columnNumber = /** @type {number} */ (event.data['columnNumber']);
+  _revealSourceLine(event: Common.EventTarget.EventTargetEvent): void {
+    const url = (event.data['url'] as string);
+    const lineNumber = (event.data['lineNumber'] as number);
+    const columnNumber = (event.data['columnNumber'] as number);
 
     const uiSourceCode = Workspace.Workspace.WorkspaceImpl.instance().uiSourceCodeForURL(url);
     if (uiSourceCode) {
@@ -551,11 +532,8 @@
       return;
     }
 
-    /**
-     * @param {!Common.EventTarget.EventTargetEvent} event
-     */
-    function listener(event) {
-      const uiSourceCode = /** @type {!Workspace.UISourceCode.UISourceCode} */ (event.data);
+    function listener(event: Common.EventTarget.EventTargetEvent): void {
+      const uiSourceCode = (event.data as Workspace.UISourceCode.UISourceCode);
       if (uiSourceCode.url() === url) {
         Common.Revealer.reveal(uiSourceCode.uiLocation(lineNumber, columnNumber));
         Workspace.Workspace.WorkspaceImpl.instance().removeEventListener(
@@ -567,23 +545,17 @@
         Workspace.Workspace.Events.UISourceCodeAdded, listener);
   }
 
-  /**
-   * @param {!Event} event
-   */
-  _postDocumentKeyDown(event) {
+  _postDocumentKeyDown(event: Event): void {
     if (!event.handled) {
-      UI.ShortcutRegistry.ShortcutRegistry.instance().handleShortcut(/** @type {!KeyboardEvent} */ (event));
+      UI.ShortcutRegistry.ShortcutRegistry.instance().handleShortcut((event as KeyboardEvent));
     }
   }
 
-  /**
-   * @param {!Event} event
-   */
-  _redispatchClipboardEvent(event) {
+  _redispatchClipboardEvent(event: Event): void {
     const eventCopy = new CustomEvent('clipboard-' + event.type, {bubbles: true});
     // @ts-ignore Used in ElementsTreeOutline
     eventCopy['original'] = event;
-    const document = event.target && /** @type {!HTMLElement} */ (event.target).ownerDocument;
+    const document = event.target && (event.target as HTMLElement).ownerDocument;
     const target = document ? document.deepActiveElement() : null;
     if (target) {
       target.dispatchEvent(eventCopy);
@@ -593,19 +565,13 @@
     }
   }
 
-  /**
-   * @param {!Event} event
-   */
-  _contextMenuEventFired(event) {
-    if (event.handled || /** @type {!HTMLElement} */ (event.target).classList.contains('popup-glasspane')) {
+  _contextMenuEventFired(event: Event): void {
+    if (event.handled || (event.target as HTMLElement).classList.contains('popup-glasspane')) {
       event.preventDefault();
     }
   }
 
-  /**
-   * @param {!Document} document
-   */
-  _addMainEventListeners(document) {
+  _addMainEventListeners(document: Document): void {
     document.addEventListener('keydown', this._postDocumentKeyDown.bind(this), false);
     document.addEventListener('beforecopy', this._redispatchClipboardEvent.bind(this), true);
     document.addEventListener('copy', this._redispatchClipboardEvent.bind(this), false);
@@ -614,31 +580,25 @@
     document.addEventListener('contextmenu', this._contextMenuEventFired.bind(this), true);
   }
 
-  _onSuspendStateChanged() {
+  _onSuspendStateChanged(): void {
     const suspended = SDK.SDKModel.TargetManager.instance().allTargetsSuspended();
     UI.InspectorView.InspectorView.instance().onSuspendStateChanged(suspended);
   }
-}
 
-/** @type {?MainImpl} */
-MainImpl._instanceForTest = null;
+  static _instanceForTest: MainImpl|null = null;
+}
 
 // @ts-ignore Exported for Tests.js
 globalThis.Main = globalThis.Main || {};
 // @ts-ignore Exported for Tests.js
 globalThis.Main.Main = MainImpl;
 
-/** @type {!ZoomActionDelegate} */
-let zoomActionDelegateInstance;
+let zoomActionDelegateInstance: ZoomActionDelegate;
 
-/**
- * @implements {UI.ActionRegistration.ActionDelegate}
- */
-export class ZoomActionDelegate {
-  /**
-   * @param {{forceNew: ?boolean}} opts
-   */
-  static instance(opts = {forceNew: null}) {
+export class ZoomActionDelegate implements UI.ActionRegistration.ActionDelegate {
+  static instance(opts: {
+    forceNew: boolean|null,
+  } = {forceNew: null}): ZoomActionDelegate {
     const {forceNew} = opts;
     if (!zoomActionDelegateInstance || forceNew) {
       zoomActionDelegateInstance = new ZoomActionDelegate();
@@ -647,13 +607,7 @@
     return zoomActionDelegateInstance;
   }
 
-  /**
-   * @override
-   * @param {!UI.Context.Context} context
-   * @param {string} actionId
-   * @return {boolean}
-   */
-  handleAction(context, actionId) {
+  handleAction(context: UI.Context.Context, actionId: string): boolean {
     if (Host.InspectorFrontendHost.InspectorFrontendHostInstance.isHostedMode()) {
       return false;
     }
@@ -673,17 +627,12 @@
   }
 }
 
-/** @type {!SearchActionDelegate} */
-let searchActionDelegateInstance;
+let searchActionDelegateInstance: SearchActionDelegate;
 
-/**
- * @implements {UI.ActionRegistration.ActionDelegate}
- */
-export class SearchActionDelegate {
-  /**
-   * @param {{forceNew: ?boolean}} opts
-   */
-  static instance(opts = {forceNew: null}) {
+export class SearchActionDelegate implements UI.ActionRegistration.ActionDelegate {
+  static instance(opts: {
+    forceNew: boolean|null,
+  } = {forceNew: null}): SearchActionDelegate {
     const {forceNew} = opts;
     if (!searchActionDelegateInstance || forceNew) {
       searchActionDelegateInstance = new SearchActionDelegate();
@@ -692,17 +641,10 @@
     return searchActionDelegateInstance;
   }
 
-  /**
-   * @override
-   * @param {!UI.Context.Context} context
-   * @param {string} actionId
-   * @return {boolean}
-   */
-  handleAction(context, actionId) {
+  handleAction(context: UI.Context.Context, actionId: string): boolean {
     let searchableView = UI.SearchableView.SearchableView.fromElement(document.deepActiveElement());
     if (!searchableView) {
-      const currentPanel =
-          /** @type {!UI.Panel.Panel} */ (UI.InspectorView.InspectorView.instance().currentPanelDeprecated());
+      const currentPanel = (UI.InspectorView.InspectorView.instance().currentPanelDeprecated() as UI.Panel.Panel);
       if (currentPanel && currentPanel.searchableView) {
         searchableView = currentPanel.searchableView();
       }
@@ -723,22 +665,18 @@
     return false;
   }
 }
-/** @type {!MainMenuItem} */
-let mainMenuItemInstance;
+let mainMenuItemInstance: MainMenuItem;
 
-/**
- * @implements {UI.Toolbar.Provider}
- */
-export class MainMenuItem {
+export class MainMenuItem implements UI.Toolbar.Provider {
+  _item: UI.Toolbar.ToolbarMenuButton;
   constructor() {
     this._item = new UI.Toolbar.ToolbarMenuButton(this._handleContextMenu.bind(this), true);
     this._item.setTitle(i18nString(UIStrings.customizeAndControlDevtools));
   }
 
-  /**
-   * @param {{forceNew: ?boolean}} opts
-   */
-  static instance(opts = {forceNew: null}) {
+  static instance(opts: {
+    forceNew: boolean|null,
+  } = {forceNew: null}): MainMenuItem {
     const {forceNew} = opts;
     if (!mainMenuItemInstance || forceNew) {
       mainMenuItemInstance = new MainMenuItem();
@@ -747,18 +685,11 @@
     return mainMenuItemInstance;
   }
 
-  /**
-   * @override
-   * @return {?UI.Toolbar.ToolbarItem}
-   */
-  item() {
+  item(): UI.Toolbar.ToolbarItem|null {
     return this._item;
   }
 
-  /**
-   * @param {!UI.ContextMenu.ContextMenu} contextMenu
-   */
-  _handleContextMenu(contextMenu) {
+  _handleContextMenu(contextMenu: UI.ContextMenu.ContextMenu): void {
     if (UI.DockController.DockController.instance().canDock()) {
       const dockItemElement = document.createElement('div');
       dockItemElement.classList.add('flex-centered');
@@ -822,13 +753,9 @@
       contextMenu.headerSection().appendCustomItem(dockItemElement);
     }
 
+    const button = (this._item.element as HTMLButtonElement);
 
-    const button = /** @type {!HTMLButtonElement} */ (this._item.element);
-
-    /**
-     * @param {string} side
-     */
-    function setDockSide(side) {
+    function setDockSide(side: string): void {
       UI.DockController.DockController.instance().once(UI.DockController.Events.AfterDockSideChanged).then(() => {
         button.focus();
       });
@@ -886,24 +813,19 @@
   }
 }
 
-/** @type {!SettingsButtonProvider} */
-let settingsButtonProviderInstance;
+let settingsButtonProviderInstance: SettingsButtonProvider;
 
-/**
- * @implements {UI.Toolbar.Provider}
- */
-export class SettingsButtonProvider {
-  /** @private */
-  constructor() {
+export class SettingsButtonProvider implements UI.Toolbar.Provider {
+  _settingsButton: UI.Toolbar.ToolbarButton;
+  private constructor() {
     const settingsActionId = 'settings.show';
     this._settingsButton =
         UI.Toolbar.Toolbar.createActionButtonForId(settingsActionId, {showLabel: false, userActionCode: undefined});
   }
 
-  /**
-   * @param {{forceNew: ?boolean}} opts
-   */
-  static instance(opts = {forceNew: null}) {
+  static instance(opts: {
+    forceNew: boolean|null,
+  } = {forceNew: null}): SettingsButtonProvider {
     const {forceNew} = opts;
     if (!settingsButtonProviderInstance || forceNew) {
       settingsButtonProviderInstance = new SettingsButtonProvider();
@@ -912,11 +834,7 @@
     return settingsButtonProviderInstance;
   }
 
-  /**
-   * @override
-   * @return {?UI.Toolbar.ToolbarItem}
-   */
-  item() {
+  item(): UI.Toolbar.ToolbarItem|null {
     return this._settingsButton;
   }
 }
@@ -927,25 +845,19 @@
         SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
   }
 
-  /**
-   * @param {!Common.EventTarget.EventTargetEvent} event
-   */
-  _debuggerPaused(event) {
+  _debuggerPaused(event: Common.EventTarget.EventTargetEvent): void {
     SDK.SDKModel.TargetManager.instance().removeModelListener(
         SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this);
-    const debuggerModel = /** @type {!SDK.DebuggerModel.DebuggerModel} */ (event.data);
+    const debuggerModel = (event.data as SDK.DebuggerModel.DebuggerModel);
     const debuggerPausedDetails = debuggerModel.debuggerPausedDetails();
     UI.Context.Context.instance().setFlavor(SDK.SDKModel.Target, debuggerModel.target());
     Common.Revealer.reveal(debuggerPausedDetails);
   }
 }
 
-/**
- * @param {string} method
- * @param {?Object} params
- * @return {!Promise<?Array<*>>}
- */
-export function sendOverProtocol(method, params) {
+// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export function sendOverProtocol(method: string, params: Object|null): Promise<any[]|null> {
   return new Promise((resolve, reject) => {
     const sendRawMessage = ProtocolClient.InspectorBackend.test.sendRawMessage;
     if (!sendRawMessage) {
@@ -960,17 +872,12 @@
   });
 }
 
-/** @type {!ReloadActionDelegate} */
-let reloadActionDelegateInstance;
+let reloadActionDelegateInstance: ReloadActionDelegate;
 
-/**
- * @implements {UI.ActionRegistration.ActionDelegate}
- */
-export class ReloadActionDelegate {
-  /**
-   * @param {{forceNew: ?boolean}} opts
-   */
-  static instance(opts = {forceNew: null}) {
+export class ReloadActionDelegate implements UI.ActionRegistration.ActionDelegate {
+  static instance(opts: {
+    forceNew: boolean|null,
+  } = {forceNew: null}): ReloadActionDelegate {
     const {forceNew} = opts;
     if (!reloadActionDelegateInstance || forceNew) {
       reloadActionDelegateInstance = new ReloadActionDelegate();
@@ -979,13 +886,7 @@
     return reloadActionDelegateInstance;
   }
 
-  /**
-   * @override
-   * @param {!UI.Context.Context} context
-   * @param {string} actionId
-   * @return {boolean}
-   */
-  handleAction(context, actionId) {
+  handleAction(context: UI.Context.Context, actionId: string): boolean {
     switch (actionId) {
       case 'main.debug-reload':
         Components.Reload.reload();
diff --git a/front_end/main/SimpleApp.js b/front_end/main/SimpleApp.js
deleted file mode 100644
index 49ea590..0000000
--- a/front_end/main/SimpleApp.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-import * as Common from '../common/common.js';  // eslint-disable-line no-unused-vars
-import * as UI from '../ui/ui.js';
-
-/**
- * @implements {Common.App.App}
- */
-export class SimpleApp {
-  /**
-   * @override
-   * @param {!Document} document
-   */
-  presentUI(document) {
-    const rootView = new UI.RootView.RootView();
-    UI.InspectorView.InspectorView.instance().show(rootView.element);
-    rootView.attachToDocument(document);
-    rootView.focus();
-  }
-}
-
-
-/** @type {!SimpleAppProvider} */
-let simpleAppProviderInstance;
-
-
-/**
- * @implements {Common.AppProvider.AppProvider}
- */
-export class SimpleAppProvider {
-  /**
-   * @param {{forceNew: ?boolean}} opts
-   */
-  static instance(opts = {forceNew: null}) {
-    const {forceNew} = opts;
-    if (!simpleAppProviderInstance || forceNew) {
-      simpleAppProviderInstance = new SimpleAppProvider();
-    }
-
-    return simpleAppProviderInstance;
-  }
-
-  /**
-   * @override
-   * @return {!Common.App.App}
-   */
-  createApp() {
-    return new SimpleApp();
-  }
-}
diff --git a/front_end/main/SimpleApp.ts b/front_end/main/SimpleApp.ts
new file mode 100644
index 0000000..75b192b
--- /dev/null
+++ b/front_end/main/SimpleApp.ts
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* eslint-disable rulesdir/no_underscored_properties */
+
+import * as Common from '../common/common.js';  // eslint-disable-line no-unused-vars
+import * as UI from '../ui/ui.js';
+
+export class SimpleApp implements Common.App.App {
+  presentUI(document: Document): void {
+    const rootView = new UI.RootView.RootView();
+    UI.InspectorView.InspectorView.instance().show(rootView.element);
+    rootView.attachToDocument(document);
+    rootView.focus();
+  }
+}
+
+let simpleAppProviderInstance: SimpleAppProvider;
+
+export class SimpleAppProvider implements Common.AppProvider.AppProvider {
+  static instance(opts: {
+    forceNew: boolean|null,
+  } = {forceNew: null}): SimpleAppProvider {
+    const {forceNew} = opts;
+    if (!simpleAppProviderInstance || forceNew) {
+      simpleAppProviderInstance = new SimpleAppProvider();
+    }
+
+    return simpleAppProviderInstance;
+  }
+
+  createApp(): Common.App.App {
+    return new SimpleApp();
+  }
+}
diff --git a/front_end/main/main-legacy.js b/front_end/main/main-legacy.ts
similarity index 100%
rename from front_end/main/main-legacy.js
rename to front_end/main/main-legacy.ts
diff --git a/scripts/check_experiments.js b/scripts/check_experiments.js
index 240ca18..1fcd199 100644
--- a/scripts/check_experiments.js
+++ b/scripts/check_experiments.js
@@ -148,7 +148,7 @@
 }
 
 function main() {
-  const mainImplPath = path.resolve(__dirname, '..', 'front_end', 'main', 'MainImpl.js');
+  const mainImplPath = path.resolve(__dirname, '..', 'front_end', 'main', 'MainImpl.ts');
   const mainImplFile = fs.readFileSync(mainImplPath, 'utf-8');
 
   const userMetricsPath = path.resolve(__dirname, '..', 'front_end', 'core', 'host', 'UserMetrics.ts');
diff --git a/scripts/eslint_rules/lib/check_license_header.js b/scripts/eslint_rules/lib/check_license_header.js
index beda014..93dbd6a 100644
--- a/scripts/eslint_rules/lib/check_license_header.js
+++ b/scripts/eslint_rules/lib/check_license_header.js
@@ -87,7 +87,7 @@
   'elements/EventListenersWidget.js',
   'elements/PropertiesWidget.js',
   'elements/StylesSidebarPane.js',
-  'main/MainImpl.js',
+  'main/MainImpl.ts',
   'platform/UIString.ts',
   'sdk/DOMModel.js',
   'sources/ScopeChainSidebarPane.js',