[ui] Refactor `NewBottomTabArgs` interface to use generic type for
`config` property.

This provides type safety when constructing bottom tabs manually, and
avoids a type assertion in the bottom tab base class.

Bug: 320916474
Change-Id: I29ef9d42cf918c4e103267f9a5718d0966256b27
diff --git a/ui/src/frontend/bottom_tab.ts b/ui/src/frontend/bottom_tab.ts
index a79cfe9..6cba1e2 100644
--- a/ui/src/frontend/bottom_tab.ts
+++ b/ui/src/frontend/bottom_tab.ts
@@ -25,11 +25,11 @@
 
 import {globals} from './globals';
 
-export interface NewBottomTabArgs {
+export interface NewBottomTabArgs<Config> {
   engine: EngineProxy;
   tag?: string;
   uuid: string;
-  config: {};
+  config: Config;
 }
 
 // Interface for allowing registration and creation of bottom tabs.
@@ -37,7 +37,7 @@
 export interface BottomTabCreator {
   readonly kind: string;
 
-  create(args: NewBottomTabArgs): BottomTab;
+  create(args: NewBottomTabArgs<unknown>): BottomTab;
 }
 
 export const bottomTabRegistry = Registry.kindRegistry<BottomTabCreator>();
@@ -78,8 +78,8 @@
   // panel.
   readonly uuid: string;
 
-  constructor(args: NewBottomTabArgs) {
-    this.config = args.config as Config;
+  constructor(args: NewBottomTabArgs<Config>) {
+    this.config = args.config;
     this.engine = args.engine;
     this.tag = args.tag;
     this.uuid = args.uuid;
@@ -110,7 +110,7 @@
 // lifecycle events. Most cases, however, don't need them and BottomTab
 // provides a simplified API for the common case.
 export abstract class BottomTab<Config = {}> extends BottomTabBase<Config> {
-  constructor(args: NewBottomTabArgs) {
+  constructor(args: NewBottomTabArgs<Config>) {
     super(args);
   }
 
diff --git a/ui/src/frontend/chrome_slice_details_tab.ts b/ui/src/frontend/chrome_slice_details_tab.ts
index 8b0066f..f5e5f160 100644
--- a/ui/src/frontend/chrome_slice_details_tab.ts
+++ b/ui/src/frontend/chrome_slice_details_tab.ts
@@ -231,11 +231,12 @@
   private sliceDetails?: SliceDetails;
   private breakdownByThreadState?: BreakdownByThreadState;
 
-  static create(args: NewBottomTabArgs): ChromeSliceDetailsTab {
+  static create(args: NewBottomTabArgs<ChromeSliceDetailsTabConfig>):
+      ChromeSliceDetailsTab {
     return new ChromeSliceDetailsTab(args);
   }
 
-  constructor(args: NewBottomTabArgs) {
+  constructor(args: NewBottomTabArgs<ChromeSliceDetailsTabConfig>) {
     super(args);
     this.load();
   }
diff --git a/ui/src/frontend/generic_slice_details_tab.ts b/ui/src/frontend/generic_slice_details_tab.ts
index 93515cf..e7ceb20 100644
--- a/ui/src/frontend/generic_slice_details_tab.ts
+++ b/ui/src/frontend/generic_slice_details_tab.ts
@@ -53,11 +53,12 @@
 
   data: {[key: string]: ColumnType}|undefined;
 
-  static create(args: NewBottomTabArgs): GenericSliceDetailsTab {
+  static create(args: NewBottomTabArgs<GenericSliceDetailsTabConfig>):
+      GenericSliceDetailsTab {
     return new GenericSliceDetailsTab(args);
   }
 
-  constructor(args: NewBottomTabArgs) {
+  constructor(args: NewBottomTabArgs<GenericSliceDetailsTabConfig>) {
     super(args);
 
     this.engine
diff --git a/ui/src/frontend/notes_panel.ts b/ui/src/frontend/notes_panel.ts
index 4078db1..4b41a17 100644
--- a/ui/src/frontend/notes_panel.ts
+++ b/ui/src/frontend/notes_panel.ts
@@ -313,11 +313,11 @@
 export class NotesEditorTab extends BottomTab<NotesEditorTabConfig> {
   static readonly kind = 'org.perfetto.NotesEditorTab';
 
-  static create(args: NewBottomTabArgs): NotesEditorTab {
+  static create(args: NewBottomTabArgs<NotesEditorTabConfig>): NotesEditorTab {
     return new NotesEditorTab(args);
   }
 
-  constructor(args: NewBottomTabArgs) {
+  constructor(args: NewBottomTabArgs<NotesEditorTabConfig>) {
     super(args);
   }
 
diff --git a/ui/src/frontend/query_result_tab.ts b/ui/src/frontend/query_result_tab.ts
index f0efe26..eb51c6e 100644
--- a/ui/src/frontend/query_result_tab.ts
+++ b/ui/src/frontend/query_result_tab.ts
@@ -64,17 +64,17 @@
   queryResponse?: QueryResponse;
   sqlViewName?: string;
 
-  static create(args: NewBottomTabArgs): QueryResultTab {
+  static create(args: NewBottomTabArgs<QueryResultTabConfig>): QueryResultTab {
     return new QueryResultTab(args);
   }
 
-  constructor(args: NewBottomTabArgs) {
+  constructor(args: NewBottomTabArgs<QueryResultTabConfig>) {
     super(args);
 
     this.initTrack(args);
   }
 
-  async initTrack(args: NewBottomTabArgs) {
+  async initTrack(args: NewBottomTabArgs<QueryResultTabConfig>) {
     let uuid = '';
     if (this.config.prefetchedResponse !== undefined) {
       this.queryResponse = this.config.prefetchedResponse;
diff --git a/ui/src/frontend/sql_table/tab.ts b/ui/src/frontend/sql_table/tab.ts
index 1629d42..5795b39 100644
--- a/ui/src/frontend/sql_table/tab.ts
+++ b/ui/src/frontend/sql_table/tab.ts
@@ -38,14 +38,14 @@
 
   private state: SqlTableState;
 
-  constructor(args: NewBottomTabArgs) {
+  constructor(args: NewBottomTabArgs<SqlTableTabConfig>) {
     super(args);
 
     this.state =
         new SqlTableState(this.engine, this.config.table, this.config.filters);
   }
 
-  static create(args: NewBottomTabArgs): SqlTableTab {
+  static create(args: NewBottomTabArgs<SqlTableTabConfig>): SqlTableTab {
     return new SqlTableTab(args);
   }
 
diff --git a/ui/src/frontend/thread_state_tab.ts b/ui/src/frontend/thread_state_tab.ts
index 8f43379..da96c65 100644
--- a/ui/src/frontend/thread_state_tab.ts
+++ b/ui/src/frontend/thread_state_tab.ts
@@ -63,11 +63,11 @@
   relatedStates?: RelatedThreadStates;
   loaded: boolean = false;
 
-  static create(args: NewBottomTabArgs): ThreadStateTab {
+  static create(args: NewBottomTabArgs<ThreadStateTabConfig>): ThreadStateTab {
     return new ThreadStateTab(args);
   }
 
-  constructor(args: NewBottomTabArgs) {
+  constructor(args: NewBottomTabArgs<ThreadStateTabConfig>) {
     super(args);
 
     this.load().then(() => {