From c60d0e7392fc708e961614d6b756a045de74f458 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Tue, 30 Apr 2019 14:00:07 +0900
Subject: Rename .js/.jsx to .ts/.tsx

---
 src/background/controllers/MarkController.ts | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 src/background/controllers/MarkController.ts

(limited to 'src/background/controllers/MarkController.ts')

diff --git a/src/background/controllers/MarkController.ts b/src/background/controllers/MarkController.ts
new file mode 100644
index 0000000..0478369
--- /dev/null
+++ b/src/background/controllers/MarkController.ts
@@ -0,0 +1,15 @@
+import MarkUseCase from '../usecases/MarkUseCase';
+
+export default class MarkController {
+  constructor() {
+    this.markUseCase = new MarkUseCase();
+  }
+
+  setGlobal(key, x, y) {
+    this.markUseCase.setGlobal(key, x, y);
+  }
+
+  jumpGlobal(key) {
+    this.markUseCase.jumpGlobal(key);
+  }
+}
-- 
cgit v1.2.3


From 678020a3a27713e77ec8d74483122b4258fbc829 Mon Sep 17 00:00:00 2001
From: Shin'ya Ueoka <ueokande@i-beam.org>
Date: Wed, 1 May 2019 11:04:24 +0900
Subject: Types on src/background

---
 .../controllers/AddonEnabledController.ts          |   4 +-
 src/background/controllers/CommandController.ts    |  14 ++-
 src/background/controllers/FindController.ts       |   6 +-
 src/background/controllers/LinkController.ts       |  12 ++-
 src/background/controllers/MarkController.ts       |  10 +-
 src/background/controllers/OperationController.ts  |  13 ++-
 src/background/controllers/SettingController.ts    |   8 +-
 src/background/controllers/VersionController.ts    |   6 +-
 src/background/controllers/version.ts              |  13 ---
 src/background/domains/CommandDocs.ts              |   3 +-
 src/background/domains/CompletionGroup.ts          |  17 +---
 src/background/domains/CompletionItem.ts           |  29 ++----
 src/background/domains/Completions.ts              |  27 ------
 src/background/domains/GlobalMark.ts               |  28 +-----
 src/background/infrastructures/ConsoleClient.ts    |  10 +-
 .../infrastructures/ContentMessageClient.ts        |  12 +--
 .../infrastructures/ContentMessageListener.ts      |  78 ++++++++++-----
 src/background/infrastructures/MemoryStorage.ts    |   6 +-
 src/background/presenters/IndicatorPresenter.ts    |   4 +-
 src/background/presenters/NotifyPresenter.ts       |   8 +-
 src/background/presenters/TabPresenter.ts          |  44 +++++----
 src/background/presenters/WindowPresenter.ts       |   2 +-
 src/background/repositories/BookmarkRepository.ts  |   4 +-
 .../repositories/BrowserSettingRepository.ts       |   2 +-
 .../repositories/CompletionsRepository.ts          |  14 ++-
 src/background/repositories/FindRepository.ts      |   6 +-
 src/background/repositories/MarkRepository.ts      |   8 +-
 .../repositories/PersistentSettingRepository.ts    |   2 +-
 src/background/repositories/SettingRepository.ts   |   8 +-
 src/background/repositories/VersionRepository.ts   |  10 --
 src/background/usecases/AddonEnabledUseCase.ts     |  18 +++-
 src/background/usecases/CommandUseCase.ts          |  52 ++++++----
 src/background/usecases/CompletionsUseCase.ts      | 107 ++++++++++++---------
 src/background/usecases/ConsoleUseCase.ts          |  40 ++++----
 src/background/usecases/FindUseCase.ts             |  14 ++-
 src/background/usecases/LinkUseCase.ts             |   8 +-
 src/background/usecases/MarkUseCase.ts             |  20 ++--
 src/background/usecases/SettingUseCase.ts          |   8 +-
 src/background/usecases/TabSelectUseCase.ts        |  24 ++---
 src/background/usecases/TabUseCase.ts              |  36 ++++---
 src/background/usecases/VersionUseCase.ts          |  10 +-
 src/background/usecases/ZoomUseCase.ts             |  26 ++---
 src/background/usecases/filters.ts                 |  38 ++++----
 src/background/usecases/parsers.ts                 |  10 +-
 src/content/scrolls.ts                             |  10 --
 test/background/domains/GlobalMark.test.ts         |  11 ---
 test/background/repositories/Mark.test.ts          |   3 +-
 test/background/repositories/Version.ts            |  34 -------
 48 files changed, 446 insertions(+), 431 deletions(-)
 delete mode 100644 src/background/controllers/version.ts
 delete mode 100644 src/background/domains/Completions.ts
 delete mode 100644 src/background/repositories/VersionRepository.ts
 delete mode 100644 test/background/domains/GlobalMark.test.ts
 delete mode 100644 test/background/repositories/Version.ts

(limited to 'src/background/controllers/MarkController.ts')

diff --git a/src/background/controllers/AddonEnabledController.ts b/src/background/controllers/AddonEnabledController.ts
index 9a3a521..251af25 100644
--- a/src/background/controllers/AddonEnabledController.ts
+++ b/src/background/controllers/AddonEnabledController.ts
@@ -1,11 +1,13 @@
 import AddonEnabledUseCase from '../usecases/AddonEnabledUseCase';
 
 export default class AddonEnabledController {
+  private addonEnabledUseCase: AddonEnabledUseCase;
+
   constructor() {
     this.addonEnabledUseCase = new AddonEnabledUseCase();
   }
 
-  indicate(enabled) {
+  indicate(enabled: boolean): Promise<any> {
     return this.addonEnabledUseCase.indicate(enabled);
   }
 }
diff --git a/src/background/controllers/CommandController.ts b/src/background/controllers/CommandController.ts
index b113709..f3a6b7f 100644
--- a/src/background/controllers/CommandController.ts
+++ b/src/background/controllers/CommandController.ts
@@ -1,19 +1,23 @@
 import CompletionsUseCase from '../usecases/CompletionsUseCase';
 import CommandUseCase from '../usecases/CommandUseCase';
-import Completions from '../domains/Completions';
+import CompletionGroup from '../domains/CompletionGroup';
 
-const trimStart = (str) => {
+const trimStart = (str: string): string => {
   // NOTE String.trimStart is available on Firefox 61
   return str.replace(/^\s+/, '');
 };
 
 export default class CommandController {
+  private completionsUseCase: CompletionsUseCase;
+
+  private commandIndicator: CommandUseCase;
+
   constructor() {
     this.completionsUseCase = new CompletionsUseCase();
     this.commandIndicator = new CommandUseCase();
   }
 
-  getCompletions(line) {
+  getCompletions(line: string): Promise<CompletionGroup[]> {
     let trimmed = trimStart(line);
     let words = trimmed.split(/ +/);
     let name = words[0];
@@ -45,11 +49,11 @@ export default class CommandController {
     case 'set':
       return this.completionsUseCase.querySet(name, keywords);
     }
-    return Promise.resolve(Completions.empty());
+    return Promise.resolve([]);
   }
 
   // eslint-disable-next-line complexity
-  exec(line) {
+  exec(line: string): Promise<any> {
     let trimmed = trimStart(line);
     let words = trimmed.split(/ +/);
     let name = words[0];
diff --git a/src/background/controllers/FindController.ts b/src/background/controllers/FindController.ts
index caeff98..28959e2 100644
--- a/src/background/controllers/FindController.ts
+++ b/src/background/controllers/FindController.ts
@@ -1,15 +1,17 @@
 import FindUseCase from '../usecases/FindUseCase';
 
 export default class FindController {
+  private findUseCase: FindUseCase;
+
   constructor() {
     this.findUseCase = new FindUseCase();
   }
 
-  getKeyword() {
+  getKeyword(): Promise<string> {
     return this.findUseCase.getKeyword();
   }
 
-  setKeyword(keyword) {
+  setKeyword(keyword: string): Promise<any> {
     return this.findUseCase.setKeyword(keyword);
   }
 }
diff --git a/src/background/controllers/LinkController.ts b/src/background/controllers/LinkController.ts
index 7e395b1..707b28a 100644
--- a/src/background/controllers/LinkController.ts
+++ b/src/background/controllers/LinkController.ts
@@ -1,15 +1,19 @@
 import LinkUseCase from '../usecases/LinkUseCase';
 
 export default class LinkController {
+  private linkUseCase: LinkUseCase;
+
   constructor() {
     this.linkUseCase = new LinkUseCase();
   }
 
-  openToTab(url, tabId) {
-    this.linkUseCase.openToTab(url, tabId);
+  openToTab(url: string, tabId: number): Promise<void> {
+    return this.linkUseCase.openToTab(url, tabId);
   }
 
-  openNewTab(url, openerId, background) {
-    this.linkUseCase.openNewTab(url, openerId, background);
+  openNewTab(
+    url: string, openerId: number, background: boolean,
+  ): Promise<void> {
+    return this.linkUseCase.openNewTab(url, openerId, background);
   }
 }
diff --git a/src/background/controllers/MarkController.ts b/src/background/controllers/MarkController.ts
index 0478369..419a08b 100644
--- a/src/background/controllers/MarkController.ts
+++ b/src/background/controllers/MarkController.ts
@@ -1,15 +1,17 @@
 import MarkUseCase from '../usecases/MarkUseCase';
 
 export default class MarkController {
+  private markUseCase: MarkUseCase;
+
   constructor() {
     this.markUseCase = new MarkUseCase();
   }
 
-  setGlobal(key, x, y) {
-    this.markUseCase.setGlobal(key, x, y);
+  setGlobal(key: string, x: number, y: number): Promise<any> {
+    return this.markUseCase.setGlobal(key, x, y);
   }
 
-  jumpGlobal(key) {
-    this.markUseCase.jumpGlobal(key);
+  jumpGlobal(key: string): Promise<any> {
+    return this.markUseCase.jumpGlobal(key);
   }
 }
diff --git a/src/background/controllers/OperationController.ts b/src/background/controllers/OperationController.ts
index 416aa9c..4e9c106 100644
--- a/src/background/controllers/OperationController.ts
+++ b/src/background/controllers/OperationController.ts
@@ -6,6 +6,16 @@ import TabSelectUseCase from '../usecases/TabSelectUseCase';
 import ZoomUseCase from '../usecases/ZoomUseCase';
 
 export default class OperationController {
+  private findUseCase: FindUseCase;
+
+  private consoleUseCase: ConsoleUseCase;
+
+  private tabUseCase: TabUseCase;
+
+  private tabSelectUseCase: TabSelectUseCase;
+
+  private zoomUseCase: ZoomUseCase;
+
   constructor() {
     this.findUseCase = new FindUseCase();
     this.consoleUseCase = new ConsoleUseCase();
@@ -15,7 +25,7 @@ export default class OperationController {
   }
 
   // eslint-disable-next-line complexity, max-lines-per-function
-  exec(operation) {
+  exec(operation: any): Promise<any> {
     switch (operation.type) {
     case operations.TAB_CLOSE:
       return this.tabUseCase.close(false);
@@ -72,6 +82,7 @@ export default class OperationController {
     case operations.CANCEL:
       return this.consoleUseCase.hideConsole();
     }
+    throw new Error('unknown operation: ' + operation.type);
   }
 }
 
diff --git a/src/background/controllers/SettingController.ts b/src/background/controllers/SettingController.ts
index e895d72..f8b7302 100644
--- a/src/background/controllers/SettingController.ts
+++ b/src/background/controllers/SettingController.ts
@@ -2,16 +2,20 @@ import SettingUseCase from '../usecases/SettingUseCase';
 import ContentMessageClient from '../infrastructures/ContentMessageClient';
 
 export default class SettingController {
+  private settingUseCase: SettingUseCase;
+
+  private contentMessageClient: ContentMessageClient;
+
   constructor() {
     this.settingUseCase = new SettingUseCase();
     this.contentMessageClient = new ContentMessageClient();
   }
 
-  getSetting() {
+  getSetting(): any {
     return this.settingUseCase.get();
   }
 
-  async reload() {
+  async reload(): Promise<any> {
     await this.settingUseCase.reload();
     this.contentMessageClient.broadcastSettingsChanged();
   }
diff --git a/src/background/controllers/VersionController.ts b/src/background/controllers/VersionController.ts
index c596f9b..f402ed0 100644
--- a/src/background/controllers/VersionController.ts
+++ b/src/background/controllers/VersionController.ts
@@ -1,11 +1,13 @@
 import VersionUseCase from '../usecases/VersionUseCase';
 
 export default class VersionController {
+  private versionUseCase: VersionUseCase;
+
   constructor() {
     this.versionUseCase = new VersionUseCase();
   }
 
-  notify() {
-    this.versionUseCase.notify();
+  notify(): void {
+    return this.versionUseCase.notify();
   }
 }
diff --git a/src/background/controllers/version.ts b/src/background/controllers/version.ts
deleted file mode 100644
index ec0f634..0000000
--- a/src/background/controllers/version.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import VersionInteractor from '../usecases/version';
-
-export default class VersionController {
-  constructor() {
-    this.versionInteractor = new VersionInteractor();
-  }
-
-  notifyIfUpdated() {
-    browser.runtime.onInstalled.addListener(() => {
-      return this.versionInteractor.notify();
-    });
-  }
-}
diff --git a/src/background/domains/CommandDocs.ts b/src/background/domains/CommandDocs.ts
index 734c68e..25ea62a 100644
--- a/src/background/domains/CommandDocs.ts
+++ b/src/background/domains/CommandDocs.ts
@@ -8,5 +8,4 @@ export default {
   bdeletes: 'Close all tabs matched by keywords',
   quit: 'Close the current tab',
   quitall: 'Close all tabs',
-};
-
+} as {[key: string]: string};
diff --git a/src/background/domains/CompletionGroup.ts b/src/background/domains/CompletionGroup.ts
index 1749d72..1eea7d8 100644
--- a/src/background/domains/CompletionGroup.ts
+++ b/src/background/domains/CompletionGroup.ts
@@ -1,14 +1,7 @@
-export default class CompletionGroup {
-  constructor(name, items) {
-    this.name0 = name;
-    this.items0 = items;
-  }
+import CompletionItem from './CompletionItem';
 
-  get name() {
-    return this.name0;
-  }
-
-  get items() {
-    return this.items0;
-  }
+export default interface CompletionGroup {
+  name: string;
+  items: CompletionItem[];
+  // eslint-disable-next-line semi
 }
diff --git a/src/background/domains/CompletionItem.ts b/src/background/domains/CompletionItem.ts
index c7ad8a1..657efaa 100644
--- a/src/background/domains/CompletionItem.ts
+++ b/src/background/domains/CompletionItem.ts
@@ -1,24 +1,7 @@
-export default class CompletionItem {
-  constructor({ caption, content, url, icon }) {
-    this.caption0 = caption;
-    this.content0 = content;
-    this.url0 = url;
-    this.icon0 = icon;
-  }
-
-  get caption() {
-    return this.caption0;
-  }
-
-  get content() {
-    return this.content0;
-  }
-
-  get url() {
-    return this.url0;
-  }
-
-  get icon() {
-    return this.icon0;
-  }
+export default interface CompletionItem {
+  readonly caption?: string;
+  readonly content?: string;
+  readonly url?: string;
+  readonly icon?: string;
+  // eslint-disable-next-line semi
 }
diff --git a/src/background/domains/Completions.ts b/src/background/domains/Completions.ts
deleted file mode 100644
index f399743..0000000
--- a/src/background/domains/Completions.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-export default class Completions {
-  constructor(groups) {
-    this.g = groups;
-  }
-
-  get groups() {
-    return this.g;
-  }
-
-  serialize() {
-    return this.groups.map(group => ({
-      name: group.name,
-      items: group.items.map(item => ({
-        caption: item.caption,
-        content: item.content,
-        url: item.url,
-        icon: item.icon,
-      })),
-    }));
-  }
-
-  static empty() {
-    return EMPTY_COMPLETIONS;
-  }
-}
-
-let EMPTY_COMPLETIONS = new Completions([]);
diff --git a/src/background/domains/GlobalMark.ts b/src/background/domains/GlobalMark.ts
index f0586f1..0964373 100644
--- a/src/background/domains/GlobalMark.ts
+++ b/src/background/domains/GlobalMark.ts
@@ -1,24 +1,6 @@
-export default class GlobalMark {
-  constructor(tabId, url, x, y) {
-    this.tabId0 = tabId;
-    this.url0 = url;
-    this.x0 = x;
-    this.y0 = y;
-  }
-
-  get tabId() {
-    return this.tabId0;
-  }
-
-  get url() {
-    return this.url0;
-  }
-
-  get x() {
-    return this.x0;
-  }
-
-  get y() {
-    return this.y0;
-  }
+export interface GlobalMark {
+  readonly tabId: number;
+  readonly url: string;
+  readonly x: number;
+  readonly y: number;
 }
diff --git a/src/background/infrastructures/ConsoleClient.ts b/src/background/infrastructures/ConsoleClient.ts
index f691515..7ad5d24 100644
--- a/src/background/infrastructures/ConsoleClient.ts
+++ b/src/background/infrastructures/ConsoleClient.ts
@@ -1,34 +1,34 @@
 import messages from '../../shared/messages';
 
 export default class ConsoleClient {
-  showCommand(tabId, command) {
+  showCommand(tabId: number, command: string): Promise<any> {
     return browser.tabs.sendMessage(tabId, {
       type: messages.CONSOLE_SHOW_COMMAND,
       command,
     });
   }
 
-  showFind(tabId) {
+  showFind(tabId: number): Promise<any> {
     return browser.tabs.sendMessage(tabId, {
       type: messages.CONSOLE_SHOW_FIND
     });
   }
 
-  showInfo(tabId, message) {
+  showInfo(tabId: number, message: string): Promise<any> {
     return browser.tabs.sendMessage(tabId, {
       type: messages.CONSOLE_SHOW_INFO,
       text: message,
     });
   }
 
-  showError(tabId, message) {
+  showError(tabId: number, message: string): Promise<any> {
     return browser.tabs.sendMessage(tabId, {
       type: messages.CONSOLE_SHOW_ERROR,
       text: message,
     });
   }
 
-  hide(tabId) {
+  hide(tabId: number): Promise<any> {
     return browser.tabs.sendMessage(tabId, {
       type: messages.CONSOLE_HIDE,
     });
diff --git a/src/background/infrastructures/ContentMessageClient.ts b/src/background/infrastructures/ContentMessageClient.ts
index 0fab5a3..20057c7 100644
--- a/src/background/infrastructures/ContentMessageClient.ts
+++ b/src/background/infrastructures/ContentMessageClient.ts
@@ -1,10 +1,10 @@
 import messages from '../../shared/messages';
 
 export default class ContentMessageClient {
-  async broadcastSettingsChanged() {
+  async broadcastSettingsChanged(): Promise<void> {
     let tabs = await browser.tabs.query({});
     for (let tab of tabs) {
-      if (tab.url.startsWith('about:')) {
+      if (!tab.id || tab.url && tab.url.startsWith('about:')) {
         continue;
       }
       browser.tabs.sendMessage(tab.id, {
@@ -13,20 +13,20 @@ export default class ContentMessageClient {
     }
   }
 
-  async getAddonEnabled(tabId) {
+  async getAddonEnabled(tabId: number): Promise<boolean> {
     let { enabled } = await browser.tabs.sendMessage(tabId, {
       type: messages.ADDON_ENABLED_QUERY,
-    });
+    }) as { enabled: boolean };
     return enabled;
   }
 
-  toggleAddonEnabled(tabId) {
+  toggleAddonEnabled(tabId: number): Promise<void> {
     return browser.tabs.sendMessage(tabId, {
       type: messages.ADDON_TOGGLE_ENABLED,
     });
   }
 
-  scrollTo(tabId, x, y) {
+  scrollTo(tabId: number, x: number, y: number): Promise<void> {
     return browser.tabs.sendMessage(tabId, {
       type: messages.TAB_SCROLL_TO,
       x,
diff --git a/src/background/infrastructures/ContentMessageListener.ts b/src/background/infrastructures/ContentMessageListener.ts
index 5b0f62e..81d3232 100644
--- a/src/background/infrastructures/ContentMessageListener.ts
+++ b/src/background/infrastructures/ContentMessageListener.ts
@@ -1,4 +1,5 @@
 import messages from '../../shared/messages';
+import CompletionGroup from '../domains/CompletionGroup';
 import CommandController from '../controllers/CommandController';
 import SettingController from '../controllers/SettingController';
 import FindController from '../controllers/FindController';
@@ -8,6 +9,22 @@ import OperationController from '../controllers/OperationController';
 import MarkController from '../controllers/MarkController';
 
 export default class ContentMessageListener {
+  private settingController: SettingController;
+
+  private commandController: CommandController;
+
+  private findController: FindController;
+
+  private addonEnabledController: AddonEnabledController;
+
+  private linkController: LinkController;
+
+  private backgroundOperationController: OperationController;
+
+  private markController: MarkController;
+
+  private consolePorts: {[tabId: number]: browser.runtime.Port};
+
   constructor() {
     this.settingController = new SettingController();
     this.commandController = new CommandController();
@@ -20,20 +37,28 @@ export default class ContentMessageListener {
     this.consolePorts = {};
   }
 
-  run() {
-    browser.runtime.onMessage.addListener((message, sender) => {
+  run(): void {
+    browser.runtime.onMessage.addListener((
+      message: any, sender: browser.runtime.MessageSender,
+    ) => {
       try {
-        let ret = this.onMessage(message, sender);
+        let ret = this.onMessage(message, sender.tab as browser.tabs.Tab);
         if (!(ret instanceof Promise)) {
           return {};
         }
         return ret.catch((e) => {
+          if (!sender.tab || !sender.tab.id) {
+            return;
+          }
           return browser.tabs.sendMessage(sender.tab.id, {
             type: messages.CONSOLE_SHOW_ERROR,
             text: e.message,
           });
         });
       } catch (e) {
+        if (!sender.tab || !sender.tab.id) {
+          return;
+        }
         return browser.tabs.sendMessage(sender.tab.id, {
           type: messages.CONSOLE_SHOW_ERROR,
           text: e.message,
@@ -43,7 +68,7 @@ export default class ContentMessageListener {
     browser.runtime.onConnect.addListener(this.onConnected.bind(this));
   }
 
-  onMessage(message, sender) {
+  onMessage(message: any, senderTab: browser.tabs.Tab): Promise<any> | any {
     switch (message.type) {
     case messages.CONSOLE_QUERY_COMPLETIONS:
       return this.onConsoleQueryCompletions(message.text);
@@ -59,7 +84,10 @@ export default class ContentMessageListener {
       return this.onAddonEnabledResponse(message.enabled);
     case messages.OPEN_URL:
       return this.onOpenUrl(
-        message.newTab, message.url, sender.tab.id, message.background);
+        message.newTab,
+        message.url,
+        senderTab.id as number,
+        message.background);
     case messages.BACKGROUND_OPERATION:
       return this.onBackgroundOperation(message.operation);
     case messages.MARK_SET_GLOBAL:
@@ -67,56 +95,60 @@ export default class ContentMessageListener {
     case messages.MARK_JUMP_GLOBAL:
       return this.onMarkJumpGlobal(message.key);
     case messages.CONSOLE_FRAME_MESSAGE:
-      return this.onConsoleFrameMessage(sender.tab.id, message.message);
+      return this.onConsoleFrameMessage(
+        senderTab.id as number, message.message,
+      );
     }
+    throw new Error('unsupported message: ' + message.type);
   }
 
-  async onConsoleQueryCompletions(line) {
+  async onConsoleQueryCompletions(line: string): Promise<CompletionGroup[]> {
     let completions = await this.commandController.getCompletions(line);
-    return Promise.resolve(completions.serialize());
+    return Promise.resolve(completions);
   }
 
-  onConsoleEnterCommand(text) {
+  onConsoleEnterCommand(text: string): Promise<any> {
     return this.commandController.exec(text);
   }
 
-
-  onSettingsQuery() {
+  onSettingsQuery(): Promise<any> {
     return this.settingController.getSetting();
   }
 
-  onFindGetKeyword() {
+  onFindGetKeyword(): Promise<string> {
     return this.findController.getKeyword();
   }
 
-  onFindSetKeyword(keyword) {
+  onFindSetKeyword(keyword: string): Promise<any> {
     return this.findController.setKeyword(keyword);
   }
 
-  onAddonEnabledResponse(enabled) {
+  onAddonEnabledResponse(enabled: boolean): Promise<any> {
     return this.addonEnabledController.indicate(enabled);
   }
 
-  onOpenUrl(newTab, url, openerId, background) {
+  onOpenUrl(
+    newTab: boolean, url: string, openerId: number, background: boolean,
+  ): Promise<any> {
     if (newTab) {
       return this.linkController.openNewTab(url, openerId, background);
     }
     return this.linkController.openToTab(url, openerId);
   }
 
-  onBackgroundOperation(operation) {
+  onBackgroundOperation(operation: any): Promise<any> {
     return this.backgroundOperationController.exec(operation);
   }
 
-  onMarkSetGlobal(key, x, y) {
+  onMarkSetGlobal(key: string, x: number, y: number): Promise<any> {
     return this.markController.setGlobal(key, x, y);
   }
 
-  onMarkJumpGlobal(key) {
+  onMarkJumpGlobal(key: string): Promise<any> {
     return this.markController.jumpGlobal(key);
   }
 
-  onConsoleFrameMessage(tabId, message) {
+  onConsoleFrameMessage(tabId: number, message: any): void {
     let port = this.consolePorts[tabId];
     if (!port) {
       return;
@@ -124,12 +156,14 @@ export default class ContentMessageListener {
     port.postMessage(message);
   }
 
-  onConnected(port) {
+  onConnected(port: browser.runtime.Port): void {
     if (port.name !== 'vimvixen-console') {
       return;
     }
 
-    let id = port.sender.tab.id;
-    this.consolePorts[id] = port;
+    if (port.sender && port.sender.tab && port.sender.tab.id) {
+      let id = port.sender.tab.id;
+      this.consolePorts[id] = port;
+    }
   }
 }
diff --git a/src/background/infrastructures/MemoryStorage.ts b/src/background/infrastructures/MemoryStorage.ts
index 3a7e4f2..baf9ffa 100644
--- a/src/background/infrastructures/MemoryStorage.ts
+++ b/src/background/infrastructures/MemoryStorage.ts
@@ -1,7 +1,7 @@
-const db = {};
+const db: {[key: string]: any} = {};
 
 export default class MemoryStorage {
-  set(name, value) {
+  set(name: string, value: any): void {
     let data = JSON.stringify(value);
     if (typeof data === 'undefined') {
       throw new Error('value is not serializable');
@@ -9,7 +9,7 @@ export default class MemoryStorage {
     db[name] = data;
   }
 
-  get(name) {
+  get(name: string): any {
     let data = db[name];
     if (!data) {
       return undefined;
diff --git a/src/background/presenters/IndicatorPresenter.ts b/src/background/presenters/IndicatorPresenter.ts
index 5737519..d9a615a 100644
--- a/src/background/presenters/IndicatorPresenter.ts
+++ b/src/background/presenters/IndicatorPresenter.ts
@@ -1,12 +1,12 @@
 export default class IndicatorPresenter {
-  indicate(enabled) {
+  indicate(enabled: boolean): Promise<void> {
     let path = enabled
       ? 'resources/enabled_32x32.png'
       : 'resources/disabled_32x32.png';
     return browser.browserAction.setIcon({ path });
   }
 
-  onClick(listener) {
+  onClick(listener: (arg: browser.tabs.Tab) => void): void {
     browser.browserAction.onClicked.addListener(listener);
   }
 }
diff --git a/src/background/presenters/NotifyPresenter.ts b/src/background/presenters/NotifyPresenter.ts
index a81f227..c83c205 100644
--- a/src/background/presenters/NotifyPresenter.ts
+++ b/src/background/presenters/NotifyPresenter.ts
@@ -1,8 +1,12 @@
 const NOTIFICATION_ID = 'vimvixen-update';
 
 export default class NotifyPresenter {
-  notify(title, message, onclick) {
-    const listener = (id) => {
+  notify(
+    title: string,
+    message: string,
+    onclick: () => void,
+  ): Promise<string> {
+    const listener = (id: string) => {
       if (id !== NOTIFICATION_ID) {
         return;
       }
diff --git a/src/background/presenters/TabPresenter.ts b/src/background/presenters/TabPresenter.ts
index 744be39..33c6513 100644
--- a/src/background/presenters/TabPresenter.ts
+++ b/src/background/presenters/TabPresenter.ts
@@ -3,27 +3,29 @@ import MemoryStorage from '../infrastructures/MemoryStorage';
 const CURRENT_SELECTED_KEY = 'tabs.current.selected';
 const LAST_SELECTED_KEY = 'tabs.last.selected';
 
+type Tab = browser.tabs.Tab;
+
 export default class TabPresenter {
-  open(url, tabId) {
+  open(url: string, tabId?: number): Promise<Tab> {
     return browser.tabs.update(tabId, { url });
   }
 
-  create(url, opts) {
+  create(url: string, opts?: object): Promise<Tab> {
     return browser.tabs.create({ url, ...opts });
   }
 
-  async getCurrent() {
+  async getCurrent(): Promise<Tab> {
     let tabs = await browser.tabs.query({
       active: true, currentWindow: true
     });
     return tabs[0];
   }
 
-  getAll() {
+  getAll(): Promise<Tab[]> {
     return browser.tabs.query({ currentWindow: true });
   }
 
-  async getLastSelectedId() {
+  async getLastSelectedId(): Promise<number | undefined> {
     let cache = new MemoryStorage();
     let tabId = await cache.get(LAST_SELECTED_KEY);
     if (tabId === null || typeof tabId === 'undefined') {
@@ -32,25 +34,25 @@ export default class TabPresenter {
     return tabId;
   }
 
-  async getByKeyword(keyword, excludePinned = false) {
+  async getByKeyword(keyword: string, excludePinned = false): Promise<Tab[]> {
     let tabs = await browser.tabs.query({ currentWindow: true });
     return tabs.filter((t) => {
-      return t.url.toLowerCase().includes(keyword.toLowerCase()) ||
+      return t.url && t.url.toLowerCase().includes(keyword.toLowerCase()) ||
         t.title && t.title.toLowerCase().includes(keyword.toLowerCase());
     }).filter((t) => {
       return !(excludePinned && t.pinned);
     });
   }
 
-  select(tabId) {
+  select(tabId: number): Promise<Tab> {
     return browser.tabs.update(tabId, { active: true });
   }
 
-  remove(ids) {
+  remove(ids: number[]): Promise<void> {
     return browser.tabs.remove(ids);
   }
 
-  async reopen() {
+  async reopen(): Promise<any> {
     let window = await browser.windows.getCurrent();
     let sessions = await browser.sessions.getRecentlyClosed();
     let session = sessions.find((s) => {
@@ -59,39 +61,43 @@ export default class TabPresenter {
     if (!session) {
       return;
     }
-    if (session.tab) {
+    if (session.tab && session.tab.sessionId) {
       return browser.sessions.restore(session.tab.sessionId);
     }
-    return browser.sessions.restore(session.window.sessionId);
+    if (session.window && session.window.sessionId) {
+      return browser.sessions.restore(session.window.sessionId);
+    }
   }
 
-  reload(tabId, cache) {
+  reload(tabId: number, cache: boolean): Promise<void> {
     return browser.tabs.reload(tabId, { bypassCache: cache });
   }
 
-  setPinned(tabId, pinned) {
+  setPinned(tabId: number, pinned: boolean): Promise<Tab> {
     return browser.tabs.update(tabId, { pinned });
   }
 
-  duplicate(id) {
+  duplicate(id: number): Promise<Tab> {
     return browser.tabs.duplicate(id);
   }
 
-  getZoom(tabId) {
+  getZoom(tabId: number): Promise<number> {
     return browser.tabs.getZoom(tabId);
   }
 
-  setZoom(tabId, factor) {
+  setZoom(tabId: number, factor: number): Promise<void> {
     return browser.tabs.setZoom(tabId, factor);
   }
 
-  onSelected(listener) {
+  onSelected(
+    listener: (arg: { tabId: number, windowId: number}) => void,
+  ): void {
     browser.tabs.onActivated.addListener(listener);
   }
 }
 
 let tabPresenter = new TabPresenter();
-tabPresenter.onSelected((tab) => {
+tabPresenter.onSelected((tab: any) => {
   let cache = new MemoryStorage();
 
   let lastId = cache.get(CURRENT_SELECTED_KEY);
diff --git a/src/background/presenters/WindowPresenter.ts b/src/background/presenters/WindowPresenter.ts
index a82c4a2..e04f258 100644
--- a/src/background/presenters/WindowPresenter.ts
+++ b/src/background/presenters/WindowPresenter.ts
@@ -1,5 +1,5 @@
 export default class WindowPresenter {
-  create(url) {
+  create(url: string): Promise<browser.windows.Window> {
     return browser.windows.create({ url });
   }
 }
diff --git a/src/background/repositories/BookmarkRepository.ts b/src/background/repositories/BookmarkRepository.ts
index 99f7ec4..b4da509 100644
--- a/src/background/repositories/BookmarkRepository.ts
+++ b/src/background/repositories/BookmarkRepository.ts
@@ -1,5 +1,7 @@
 export default class BookmarkRepository {
-  async create(title, url) {
+  async create(
+    title: string, url: string
+  ): Promise<browser.bookmarks.BookmarkTreeNode> {
     let item = await browser.bookmarks.create({
       type: 'bookmark',
       title,
diff --git a/src/background/repositories/BrowserSettingRepository.ts b/src/background/repositories/BrowserSettingRepository.ts
index a9d2c06..48c72a5 100644
--- a/src/background/repositories/BrowserSettingRepository.ts
+++ b/src/background/repositories/BrowserSettingRepository.ts
@@ -1,7 +1,7 @@
 import * as urls from '../../shared/urls';
 
 export default class BrowserSettingRepository {
-  async getHomepageUrls() {
+  async getHomepageUrls(): Promise<string[]> {
     let { value } = await browser.browserSettings.homepageOverride.get({});
     return value.split('|').map(urls.normalizeUrl);
   }
diff --git a/src/background/repositories/CompletionsRepository.ts b/src/background/repositories/CompletionsRepository.ts
index 1318d36..18af587 100644
--- a/src/background/repositories/CompletionsRepository.ts
+++ b/src/background/repositories/CompletionsRepository.ts
@@ -1,7 +1,13 @@
+type Tab = browser.tabs.Tab;
+type BookmarkTreeNode = browser.bookmarks.BookmarkTreeNode;
+
 export default class CompletionsRepository {
-  async queryBookmarks(keywords) {
+  async queryBookmarks(keywords: string): Promise<BookmarkTreeNode[]> {
     let items = await browser.bookmarks.search({ query: keywords });
     return items.filter((item) => {
+      if (!item.url) {
+        return false;
+      }
       let url = undefined;
       try {
         url = new URL(item.url);
@@ -12,17 +18,17 @@ export default class CompletionsRepository {
     });
   }
 
-  queryHistories(keywords) {
+  queryHistories(keywords: string): Promise<browser.history.HistoryItem[]> {
     return browser.history.search({
       text: keywords,
       startTime: 0,
     });
   }
 
-  async queryTabs(keywords, excludePinned) {
+  async queryTabs(keywords: string, excludePinned: boolean): Promise<Tab[]> {
     let tabs = await browser.tabs.query({ currentWindow: true });
     return tabs.filter((t) => {
-      return t.url.toLowerCase().includes(keywords.toLowerCase()) ||
+      return t.url && t.url.toLowerCase().includes(keywords.toLowerCase()) ||
         t.title && t.title.toLowerCase().includes(keywords.toLowerCase());
     }).filter((t) => {
       return !(excludePinned && t.pinned);
diff --git a/src/background/repositories/FindRepository.ts b/src/background/repositories/FindRepository.ts
index 74ec914..bf286e6 100644
--- a/src/background/repositories/FindRepository.ts
+++ b/src/background/repositories/FindRepository.ts
@@ -3,15 +3,17 @@ import MemoryStorage from '../infrastructures/MemoryStorage';
 const FIND_KEYWORD_KEY = 'find-keyword';
 
 export default class FindRepository {
+  private cache: MemoryStorage;
+
   constructor() {
     this.cache = new MemoryStorage();
   }
 
-  getKeyword() {
+  getKeyword(): Promise<string> {
     return Promise.resolve(this.cache.get(FIND_KEYWORD_KEY));
   }
 
-  setKeyword(keyword) {
+  setKeyword(keyword: string): Promise<any> {
     this.cache.set(FIND_KEYWORD_KEY, keyword);
     return Promise.resolve();
   }
diff --git a/src/background/repositories/MarkRepository.ts b/src/background/repositories/MarkRepository.ts
index 282c712..69c85f6 100644
--- a/src/background/repositories/MarkRepository.ts
+++ b/src/background/repositories/MarkRepository.ts
@@ -4,21 +4,23 @@ import GlobalMark from '../domains/GlobalMark';
 const MARK_KEY = 'mark';
 
 export default class MarkRepository {
+  private cache: MemoryStorage;
+
   constructor() {
     this.cache = new MemoryStorage();
   }
 
-  getMark(key) {
+  getMark(key: string): Promise<GlobalMark | undefined> {
     let marks = this.getOrEmptyMarks();
     let data = marks[key];
     if (!data) {
       return Promise.resolve(undefined);
     }
-    let mark = new GlobalMark(data.tabId, data.url, data.x, data.y);
+    let mark = { tabId: data.tabId, url: data.url, x: data.x, y: data.y };
     return Promise.resolve(mark);
   }
 
-  setMark(key, mark) {
+  setMark(key: string, mark: GlobalMark): Promise<any> {
     let marks = this.getOrEmptyMarks();
     marks[key] = { tabId: mark.tabId, url: mark.url, x: mark.x, y: mark.y };
     this.cache.set(MARK_KEY, marks);
diff --git a/src/background/repositories/PersistentSettingRepository.ts b/src/background/repositories/PersistentSettingRepository.ts
index 4cab107..3f2f4a1 100644
--- a/src/background/repositories/PersistentSettingRepository.ts
+++ b/src/background/repositories/PersistentSettingRepository.ts
@@ -1,7 +1,7 @@
 import Setting from '../domains/Setting';
 
 export default class SettingRepository {
-  async load() {
+  async load(): Promise<any> {
     let { settings } = await browser.storage.local.get('settings');
     if (!settings) {
       return null;
diff --git a/src/background/repositories/SettingRepository.ts b/src/background/repositories/SettingRepository.ts
index c4667a9..15355ba 100644
--- a/src/background/repositories/SettingRepository.ts
+++ b/src/background/repositories/SettingRepository.ts
@@ -3,19 +3,21 @@ import MemoryStorage from '../infrastructures/MemoryStorage';
 const CACHED_SETTING_KEY = 'setting';
 
 export default class SettingRepository {
+  private cache: MemoryStorage;
+
   constructor() {
     this.cache = new MemoryStorage();
   }
 
-  get() {
+  get(): Promise<any> {
     return Promise.resolve(this.cache.get(CACHED_SETTING_KEY));
   }
 
-  update(value) {
+  update(value: any): any {
     return this.cache.set(CACHED_SETTING_KEY, value);
   }
 
-  async setProperty(name, value) {
+  async setProperty(name: string, value: string): Promise<any> {
     let current = await this.get();
     current.properties[name] = value;
     return this.update(current);
diff --git a/src/background/repositories/VersionRepository.ts b/src/background/repositories/VersionRepository.ts
deleted file mode 100644
index 4c71d05..0000000
--- a/src/background/repositories/VersionRepository.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export default class VersionRepository {
-  async get() {
-    let { version } = await browser.storage.local.get('version');
-    return version;
-  }
-
-  update(version) {
-    return browser.storage.local.set({ version });
-  }
-}
diff --git a/src/background/usecases/AddonEnabledUseCase.ts b/src/background/usecases/AddonEnabledUseCase.ts
index bb2c347..0a6fb03 100644
--- a/src/background/usecases/AddonEnabledUseCase.ts
+++ b/src/background/usecases/AddonEnabledUseCase.ts
@@ -3,10 +3,20 @@ import TabPresenter from '../presenters/TabPresenter';
 import ContentMessageClient from '../infrastructures/ContentMessageClient';
 
 export default class AddonEnabledUseCase {
+  private indicatorPresentor: IndicatorPresenter;
+
+  private tabPresenter: TabPresenter;
+
+  private contentMessageClient: ContentMessageClient;
+
   constructor() {
     this.indicatorPresentor = new IndicatorPresenter();
 
-    this.indicatorPresentor.onClick(tab => this.onIndicatorClick(tab.id));
+    this.indicatorPresentor.onClick((tab) => {
+      if (tab.id) {
+        this.onIndicatorClick(tab.id);
+      }
+    });
 
     this.tabPresenter = new TabPresenter();
     this.tabPresenter.onSelected(info => this.onTabSelected(info.tabId));
@@ -14,15 +24,15 @@ export default class AddonEnabledUseCase {
     this.contentMessageClient = new ContentMessageClient();
   }
 
-  indicate(enabled) {
+  indicate(enabled: boolean): Promise<void> {
     return this.indicatorPresentor.indicate(enabled);
   }
 
-  onIndicatorClick(tabId) {
+  onIndicatorClick(tabId: number): Promise<void> {
     return this.contentMessageClient.toggleAddonEnabled(tabId);
   }
 
-  async onTabSelected(tabId) {
+  async onTabSelected(tabId: number): Promise<void> {
     let enabled = await this.contentMessageClient.getAddonEnabled(tabId);
     return this.indicatorPresentor.indicate(enabled);
   }
diff --git a/src/background/usecases/CommandUseCase.ts b/src/background/usecases/CommandUseCase.ts
index 9ec46fe..e0e3ada 100644
--- a/src/background/usecases/CommandUseCase.ts
+++ b/src/background/usecases/CommandUseCase.ts
@@ -6,9 +6,21 @@ import SettingRepository from '../repositories/SettingRepository';
 import BookmarkRepository from '../repositories/BookmarkRepository';
 import ConsoleClient from '../infrastructures/ConsoleClient';
 import ContentMessageClient from '../infrastructures/ContentMessageClient';
-import * as properties from 'shared/settings/properties';
+import * as properties from '../../shared/settings/properties';
 
 export default class CommandIndicator {
+  private tabPresenter: TabPresenter;
+
+  private windowPresenter: WindowPresenter;
+
+  private settingRepository: SettingRepository;
+
+  private bookmarkRepository: BookmarkRepository;
+
+  private consoleClient: ConsoleClient;
+
+  private contentMessageClient: ContentMessageClient;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
     this.windowPresenter = new WindowPresenter();
@@ -19,34 +31,34 @@ export default class CommandIndicator {
     this.contentMessageClient = new ContentMessageClient();
   }
 
-  async open(keywords) {
+  async open(keywords: string): Promise<browser.tabs.Tab> {
     let url = await this.urlOrSearch(keywords);
     return this.tabPresenter.open(url);
   }
 
-  async tabopen(keywords) {
+  async tabopen(keywords: string): Promise<browser.tabs.Tab> {
     let url = await this.urlOrSearch(keywords);
     return this.tabPresenter.create(url);
   }
 
-  async winopen(keywords) {
+  async winopen(keywords: string): Promise<browser.windows.Window> {
     let url = await this.urlOrSearch(keywords);
     return this.windowPresenter.create(url);
   }
 
   // eslint-disable-next-line max-statements
-  async buffer(keywords) {
+  async buffer(keywords: string): Promise<any> {
     if (keywords.length === 0) {
       return;
     }
 
-    if (!isNaN(keywords)) {
+    if (!isNaN(Number(keywords))) {
       let tabs = await this.tabPresenter.getAll();
       let index = parseInt(keywords, 10) - 1;
       if (index < 0 || tabs.length <= index) {
         throw new RangeError(`tab ${index + 1} does not exist`);
       }
-      return this.tabPresenter.select(tabs[index].id);
+      return this.tabPresenter.select(tabs[index].id as number);
     } else if (keywords.trim() === '%') {
       // Select current window
       return;
@@ -66,13 +78,13 @@ export default class CommandIndicator {
     }
     for (let tab of tabs) {
       if (tab.index > current.index) {
-        return this.tabPresenter.select(tab.id);
+        return this.tabPresenter.select(tab.id as number);
       }
     }
-    return this.tabPresenter.select(tabs[0].id);
+    return this.tabPresenter.select(tabs[0].id as number);
   }
 
-  async bdelete(force, keywords) {
+  async bdelete(force: boolean, keywords: string): Promise<any> {
     let excludePinned = !force;
     let tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned);
     if (tabs.length === 0) {
@@ -80,35 +92,35 @@ export default class CommandIndicator {
     } else if (tabs.length > 1) {
       throw new Error('More than one match for ' + keywords);
     }
-    return this.tabPresenter.remove([tabs[0].id]);
+    return this.tabPresenter.remove([tabs[0].id as number]);
   }
 
-  async bdeletes(force, keywords) {
+  async bdeletes(force: boolean, keywords: string): Promise<any> {
     let excludePinned = !force;
     let tabs = await this.tabPresenter.getByKeyword(keywords, excludePinned);
-    let ids = tabs.map(tab => tab.id);
+    let ids = tabs.map(tab => tab.id as number);
     return this.tabPresenter.remove(ids);
   }
 
-  async quit() {
+  async quit(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.remove([tab.id]);
+    return this.tabPresenter.remove([tab.id as number]);
   }
 
-  async quitAll() {
+  async quitAll(): Promise<any> {
     let tabs = await this.tabPresenter.getAll();
-    let ids = tabs.map(tab => tab.id);
+    let ids = tabs.map(tab => tab.id as number);
     this.tabPresenter.remove(ids);
   }
 
-  async addbookmark(title) {
+  async addbookmark(title: string): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     let item = await this.bookmarkRepository.create(title, tab.url);
     let message = 'Saved current page: ' + item.url;
     return this.consoleClient.showInfo(tab.id, message);
   }
 
-  async set(keywords) {
+  async set(keywords: string): Promise<any> {
     if (keywords.length === 0) {
       return;
     }
@@ -118,7 +130,7 @@ export default class CommandIndicator {
     return this.contentMessageClient.broadcastSettingsChanged();
   }
 
-  async urlOrSearch(keywords) {
+  async urlOrSearch(keywords: string): Promise<any> {
     let settings = await this.settingRepository.get();
     return urls.searchUrl(keywords, settings.search);
   }
diff --git a/src/background/usecases/CompletionsUseCase.ts b/src/background/usecases/CompletionsUseCase.ts
index 7dc30ac..037d6eb 100644
--- a/src/background/usecases/CompletionsUseCase.ts
+++ b/src/background/usecases/CompletionsUseCase.ts
@@ -1,6 +1,5 @@
-import CompletionItem from '../domains/CompletionItem';
-import CompletionGroup from '../domains/CompletionGroup';
 import Completions from '../domains/Completions';
+import CompletionGroup from '../domains/CompletionGroup';
 import CommandDocs from '../domains/CommandDocs';
 import CompletionsRepository from '../repositories/CompletionsRepository';
 import * as filters from './filters';
@@ -10,14 +9,23 @@ import * as properties from '../../shared/settings/properties';
 
 const COMPLETION_ITEM_LIMIT = 10;
 
+type Tab = browser.tabs.Tab;
+type HistoryItem = browser.history.HistoryItem;
+
 export default class CompletionsUseCase {
+  private tabPresenter: TabPresenter;
+
+  private completionsRepository: CompletionsRepository;
+
+  private settingRepository: SettingRepository;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
     this.completionsRepository = new CompletionsRepository();
     this.settingRepository = new SettingRepository();
   }
 
-  queryConsoleCommand(prefix) {
+  queryConsoleCommand(prefix: string): Promise<Completions> {
     let keys = Object.keys(CommandDocs);
     let items = keys
       .filter(name => name.startsWith(prefix))
@@ -28,16 +36,14 @@ export default class CompletionsUseCase {
       }));
 
     if (items.length === 0) {
-      return Promise.resolve(Completions.empty());
+      return Promise.resolve([]);
     }
-    return Promise.resolve(
-      new Completions([new CompletionGroup('Console Command', items)])
-    );
+    return Promise.resolve([{ name: 'Console CompletionGroup', items }]);
   }
 
-  async queryOpen(name, keywords) {
+  async queryOpen(name: string, keywords: string): Promise<Completions> {
     let settings = await this.settingRepository.get();
-    let groups = [];
+    let groups: CompletionGroup[] = [];
 
     let complete = settings.properties.complete || properties.defaults.complete;
     for (let c of complete) {
@@ -45,31 +51,31 @@ export default class CompletionsUseCase {
         // eslint-disable-next-line no-await-in-loop
         let engines = await this.querySearchEngineItems(name, keywords);
         if (engines.length > 0) {
-          groups.push(new CompletionGroup('Search Engines', engines));
+          groups.push({ name: 'Search Engines', items: engines });
         }
       } else if (c === 'h') {
         // eslint-disable-next-line no-await-in-loop
         let histories = await this.queryHistoryItems(name, keywords);
         if (histories.length > 0) {
-          groups.push(new CompletionGroup('History', histories));
+          groups.push({ name: 'History', items: histories });
         }
       } else if (c === 'b') {
         // eslint-disable-next-line no-await-in-loop
         let bookmarks = await this.queryBookmarkItems(name, keywords);
         if (bookmarks.length > 0) {
-          groups.push(new CompletionGroup('Bookmarks', bookmarks));
+          groups.push({ name: 'Bookmarks', items: bookmarks });
         }
       }
     }
-    return new Completions(groups);
+    return groups;
   }
 
   // eslint-disable-next-line max-statements
-  async queryBuffer(name, keywords) {
+  async queryBuffer(name: string, keywords: string): Promise<Completions> {
     let lastId = await this.tabPresenter.getLastSelectedId();
     let trimmed = keywords.trim();
-    let tabs = [];
-    if (trimmed.length > 0 && !isNaN(trimmed)) {
+    let tabs: Tab[] = [];
+    if (trimmed.length > 0 && !isNaN(Number(trimmed))) {
       let all = await this.tabPresenter.getAll();
       let index = parseInt(trimmed, 10) - 1;
       if (index >= 0 && index < all.length) {
@@ -77,18 +83,18 @@ export default class CompletionsUseCase {
       }
     } else if (trimmed === '%') {
       let all = await this.tabPresenter.getAll();
-      let tab = all.find(t => t.active);
+      let tab = all.find(t => t.active) as Tab;
       tabs = [tab];
     } else if (trimmed === '#') {
       if (typeof lastId !== 'undefined' && lastId !== null) {
         let all = await this.tabPresenter.getAll();
-        let tab = all.find(t => t.id === lastId);
+        let tab = all.find(t => t.id === lastId) as Tab;
         tabs = [tab];
       }
     } else {
       tabs = await this.completionsRepository.queryTabs(keywords, false);
     }
-    const flag = (tab) => {
+    const flag = (tab: Tab) => {
       if (tab.active) {
         return '%';
       } else if (tab.id === lastId) {
@@ -96,87 +102,90 @@ export default class CompletionsUseCase {
       }
       return ' ';
     };
-    let items = tabs.map(tab => new CompletionItem({
+    let items = tabs.map(tab => ({
       caption: tab.index + 1 + ': ' + flag(tab) + ' ' + tab.title,
       content: name + ' ' + tab.title,
       url: tab.url,
-      icon: tab.favIconUrl
+      icon: tab.favIconUrl,
     }));
     if (items.length === 0) {
-      return Promise.resolve(Completions.empty());
+      return Promise.resolve([]);
     }
-    return new Completions([new CompletionGroup('Buffers', items)]);
+    return [{ name: 'Buffers', items }];
   }
 
-  queryBdelete(name, keywords) {
+  queryBdelete(name: string, keywords: string): Promise<CompletionGroup[]> {
     return this.queryTabs(name, true, keywords);
   }
 
-  queryBdeleteForce(name, keywords) {
+  queryBdeleteForce(
+    name: string, keywords: string,
+  ): Promise<CompletionGroup[]> {
     return this.queryTabs(name, false, keywords);
   }
 
-  querySet(name, keywords) {
+  querySet(name: string, keywords: string): Promise<CompletionGroup[]> {
     let items = Object.keys(properties.docs).map((key) => {
       if (properties.types[key] === 'boolean') {
         return [
-          new CompletionItem({
+          {
             caption: key,
             content: name + ' ' + key,
             url: 'Enable ' + properties.docs[key],
-          }),
-          new CompletionItem({
+          }, {
             caption: 'no' + key,
             content: name + ' no' + key,
             url: 'Disable ' + properties.docs[key],
-          }),
+          }
         ];
       }
       return [
-        new CompletionItem({
+        {
           caption: key,
           content: name + ' ' + key,
           url: 'Set ' + properties.docs[key],
-        })
+        }
       ];
     });
-    items = items.reduce((acc, val) => acc.concat(val), []);
-    items = items.filter((item) => {
+    let flatten = items.reduce((acc, val) => acc.concat(val), []);
+    flatten = flatten.filter((item) => {
       return item.caption.startsWith(keywords);
     });
-    if (items.length === 0) {
-      return Promise.resolve(Completions.empty());
+    if (flatten.length === 0) {
+      return Promise.resolve([]);
     }
     return Promise.resolve(
-      new Completions([new CompletionGroup('Properties', items)])
+      [{ name: 'Properties', items: flatten }],
     );
   }
 
-  async queryTabs(name, excludePinned, args) {
+  async queryTabs(
+    name: string, excludePinned: boolean, args: string,
+  ): Promise<CompletionGroup[]> {
     let tabs = await this.completionsRepository.queryTabs(args, excludePinned);
-    let items = tabs.map(tab => new CompletionItem({
+    let items = tabs.map(tab => ({
       caption: tab.title,
       content: name + ' ' + tab.title,
       url: tab.url,
       icon: tab.favIconUrl
     }));
     if (items.length === 0) {
-      return Promise.resolve(Completions.empty());
+      return Promise.resolve([]);
     }
-    return new Completions([new CompletionGroup('Buffers', items)]);
+    return [{ name: 'Buffers', items }];
   }
 
-  async querySearchEngineItems(name, keywords) {
+  async querySearchEngineItems(name: string, keywords: string) {
     let settings = await this.settingRepository.get();
     let engines = Object.keys(settings.search.engines)
       .filter(key => key.startsWith(keywords));
-    return engines.map(key => new CompletionItem({
+    return engines.map(key => ({
       caption: key,
       content: name + ' ' + key,
     }));
   }
 
-  async queryHistoryItems(name, keywords) {
+  async queryHistoryItems(name: string, keywords: string) {
     let histories = await this.completionsRepository.queryHistories(keywords);
     histories = [histories]
       .map(filters.filterBlankTitle)
@@ -184,19 +193,21 @@ export default class CompletionsUseCase {
       .map(filters.filterByTailingSlash)
       .map(pages => filters.filterByPathname(pages, COMPLETION_ITEM_LIMIT))
       .map(pages => filters.filterByOrigin(pages, COMPLETION_ITEM_LIMIT))[0]
-      .sort((x, y) => x.visitCount < y.visitCount)
+      .sort((x: HistoryItem, y: HistoryItem) => {
+        return Number(x.visitCount) < Number(y.visitCount);
+      })
       .slice(0, COMPLETION_ITEM_LIMIT);
-    return histories.map(page => new CompletionItem({
+    return histories.map(page => ({
       caption: page.title,
       content: name + ' ' + page.url,
       url: page.url
     }));
   }
 
-  async queryBookmarkItems(name, keywords) {
+  async queryBookmarkItems(name: string, keywords: string) {
     let bookmarks = await this.completionsRepository.queryBookmarks(keywords);
     return bookmarks.slice(0, COMPLETION_ITEM_LIMIT)
-      .map(page => new CompletionItem({
+      .map(page => ({
         caption: page.title,
         content: name + ' ' + page.url,
         url: page.url
diff --git a/src/background/usecases/ConsoleUseCase.ts b/src/background/usecases/ConsoleUseCase.ts
index e8e5d4a..60c0439 100644
--- a/src/background/usecases/ConsoleUseCase.ts
+++ b/src/background/usecases/ConsoleUseCase.ts
@@ -2,60 +2,64 @@ import TabPresenter from '../presenters/TabPresenter';
 import ConsoleClient from '../infrastructures/ConsoleClient';
 
 export default class ConsoleUseCase {
+  private tabPresenter: TabPresenter;
+
+  private consoleClient: ConsoleClient;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
     this.consoleClient = new ConsoleClient();
   }
 
-  async showCommand() {
+  async showCommand(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    return this.consoleClient.showCommand(tab.id, '');
+    return this.consoleClient.showCommand(tab.id as number, '');
   }
 
-  async showOpenCommand(alter) {
+  async showOpenCommand(alter: boolean): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     let command = 'open ';
     if (alter) {
-      command += tab.url;
+      command += tab.url || '';
     }
-    return this.consoleClient.showCommand(tab.id, command);
+    return this.consoleClient.showCommand(tab.id as number, command);
   }
 
-  async showTabopenCommand(alter) {
+  async showTabopenCommand(alter: boolean): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     let command = 'tabopen ';
     if (alter) {
-      command += tab.url;
+      command += tab.url || '';
     }
-    return this.consoleClient.showCommand(tab.id, command);
+    return this.consoleClient.showCommand(tab.id as number, command);
   }
 
-  async showWinopenCommand(alter) {
+  async showWinopenCommand(alter: boolean): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     let command = 'winopen ';
     if (alter) {
-      command += tab.url;
+      command += tab.url || '';
     }
-    return this.consoleClient.showCommand(tab.id, command);
+    return this.consoleClient.showCommand(tab.id as number, command);
   }
 
-  async showBufferCommand() {
+  async showBufferCommand(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     let command = 'buffer ';
-    return this.consoleClient.showCommand(tab.id, command);
+    return this.consoleClient.showCommand(tab.id as number, command);
   }
 
-  async showAddbookmarkCommand(alter) {
+  async showAddbookmarkCommand(alter: boolean): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     let command = 'addbookmark ';
     if (alter) {
-      command += tab.title;
+      command += tab.title || '';
     }
-    return this.consoleClient.showCommand(tab.id, command);
+    return this.consoleClient.showCommand(tab.id as number, command);
   }
 
-  async hideConsole() {
+  async hideConsole(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    return this.consoleClient.hide(tab.id);
+    return this.consoleClient.hide(tab.id as number);
   }
 }
diff --git a/src/background/usecases/FindUseCase.ts b/src/background/usecases/FindUseCase.ts
index 224e4a9..d567800 100644
--- a/src/background/usecases/FindUseCase.ts
+++ b/src/background/usecases/FindUseCase.ts
@@ -3,22 +3,28 @@ import TabPresenter from '../presenters/TabPresenter';
 import ConsoleClient from '../infrastructures/ConsoleClient';
 
 export default class FindUseCase {
+  private tabPresenter: TabPresenter;
+
+  private findRepository: FindRepository;
+
+  private consoleClient: ConsoleClient;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
     this.findRepository = new FindRepository();
     this.consoleClient = new ConsoleClient();
   }
 
-  getKeyword() {
+  getKeyword(): Promise<string> {
     return this.findRepository.getKeyword();
   }
 
-  setKeyword(keyword) {
+  setKeyword(keyword: string): Promise<any> {
     return this.findRepository.setKeyword(keyword);
   }
 
-  async findStart() {
+  async findStart(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    return this.consoleClient.showFind(tab.id);
+    return this.consoleClient.showFind(tab.id as number);
   }
 }
diff --git a/src/background/usecases/LinkUseCase.ts b/src/background/usecases/LinkUseCase.ts
index 89412c5..2f4df7b 100644
--- a/src/background/usecases/LinkUseCase.ts
+++ b/src/background/usecases/LinkUseCase.ts
@@ -1,17 +1,17 @@
-import SettingRepository from '../repositories/SettingRepository';
 import TabPresenter from '../presenters/TabPresenter';
 
 export default class LinkUseCase {
+  private tabPresenter: TabPresenter;
+
   constructor() {
-    this.settingRepository = new SettingRepository();
     this.tabPresenter = new TabPresenter();
   }
 
-  openToTab(url, tabId) {
+  openToTab(url: string, tabId: number): Promise<any> {
     return this.tabPresenter.open(url, tabId);
   }
 
-  openNewTab(url, openerId, background) {
+  openNewTab(url: string, openerId: number, background: boolean): Promise<any> {
     return this.tabPresenter.create(url, {
       openerTabId: openerId, active: !background
     });
diff --git a/src/background/usecases/MarkUseCase.ts b/src/background/usecases/MarkUseCase.ts
index 39c796b..8b544aa 100644
--- a/src/background/usecases/MarkUseCase.ts
+++ b/src/background/usecases/MarkUseCase.ts
@@ -1,10 +1,17 @@
-import GlobalMark from '../domains/GlobalMark';
 import TabPresenter from '../presenters/TabPresenter';
 import MarkRepository from '../repositories/MarkRepository';
 import ConsoleClient from '../infrastructures/ConsoleClient';
 import ContentMessageClient from '../infrastructures/ContentMessageClient';
 
 export default class MarkUseCase {
+  private tabPresenter: TabPresenter;
+
+  private markRepository: MarkRepository;
+
+  private consoleClient: ConsoleClient;
+
+  private contentMessageClient: ContentMessageClient;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
     this.markRepository = new MarkRepository();
@@ -12,18 +19,19 @@ export default class MarkUseCase {
     this.contentMessageClient = new ContentMessageClient();
   }
 
-  async setGlobal(key, x, y) {
+  async setGlobal(key: string, x: number, y: number): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    let mark = new GlobalMark(tab.id, tab.url, x, y);
+    let mark = { tabId: tab.id, url: tab.url, x, y };
     return this.markRepository.setMark(key, mark);
   }
 
-  async jumpGlobal(key) {
+  async jumpGlobal(key: string): Promise<any> {
     let current = await this.tabPresenter.getCurrent();
 
     let mark = await this.markRepository.getMark(key);
     if (!mark) {
-      return this.consoleClient.showError(current.id, 'Mark is not set');
+      return this.consoleClient.showError(
+        current.id as number, 'Mark is not set');
     }
 
     return this.contentMessageClient.scrollTo(
@@ -32,7 +40,7 @@ export default class MarkUseCase {
       return this.tabPresenter.select(mark.tabId);
     }).catch(async() => {
       let tab = await this.tabPresenter.create(mark.url);
-      let mark2 = new GlobalMark(tab.id, mark.url, mark.x, mark.y);
+      let mark2 = { tabId: tab.id, url: mark.url, x: mark.x, y: mark.y };
       return this.markRepository.setMark(key, mark2);
     });
   }
diff --git a/src/background/usecases/SettingUseCase.ts b/src/background/usecases/SettingUseCase.ts
index 9e17408..b66ce02 100644
--- a/src/background/usecases/SettingUseCase.ts
+++ b/src/background/usecases/SettingUseCase.ts
@@ -4,16 +4,20 @@ import PersistentSettingRepository from '../repositories/PersistentSettingReposi
 import SettingRepository from '../repositories/SettingRepository';
 
 export default class SettingUseCase {
+  private persistentSettingRepository: PersistentSettingRepository;
+
+  private settingRepository: SettingRepository;
+
   constructor() {
     this.persistentSettingRepository = new PersistentSettingRepository();
     this.settingRepository = new SettingRepository();
   }
 
-  get() {
+  get(): Promise<any> {
     return this.settingRepository.get();
   }
 
-  async reload() {
+  async reload(): Promise<any> {
     let settings = await this.persistentSettingRepository.load();
     if (!settings) {
       settings = Setting.defaultSettings();
diff --git a/src/background/usecases/TabSelectUseCase.ts b/src/background/usecases/TabSelectUseCase.ts
index 16b3e14..a0b52f0 100644
--- a/src/background/usecases/TabSelectUseCase.ts
+++ b/src/background/usecases/TabSelectUseCase.ts
@@ -1,11 +1,13 @@
 import TabPresenter from '../presenters/TabPresenter';
 
 export default class TabSelectUseCase {
+  private tabPresenter: TabPresenter;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
   }
 
-  async selectPrev(count) {
+  async selectPrev(count: number): Promise<any> {
     let tabs = await this.tabPresenter.getAll();
     if (tabs.length < 2) {
       return;
@@ -15,10 +17,10 @@ export default class TabSelectUseCase {
       return;
     }
     let select = (tab.index - count + tabs.length) % tabs.length;
-    return this.tabPresenter.select(tabs[select].id);
+    return this.tabPresenter.select(tabs[select].id as number);
   }
 
-  async selectNext(count) {
+  async selectNext(count: number): Promise<any> {
     let tabs = await this.tabPresenter.getAll();
     if (tabs.length < 2) {
       return;
@@ -28,24 +30,24 @@ export default class TabSelectUseCase {
       return;
     }
     let select = (tab.index + count) % tabs.length;
-    return this.tabPresenter.select(tabs[select].id);
+    return this.tabPresenter.select(tabs[select].id as number);
   }
 
-  async selectFirst() {
+  async selectFirst(): Promise<any> {
     let tabs = await this.tabPresenter.getAll();
-    return this.tabPresenter.select(tabs[0].id);
+    return this.tabPresenter.select(tabs[0].id as number);
   }
 
-  async selectLast() {
+  async selectLast(): Promise<any> {
     let tabs = await this.tabPresenter.getAll();
-    return this.tabPresenter.select(tabs[tabs.length - 1].id);
+    return this.tabPresenter.select(tabs[tabs.length - 1].id as number);
   }
 
-  async selectPrevSelected() {
+  async selectPrevSelected(): Promise<any> {
     let tabId = await this.tabPresenter.getLastSelectedId();
     if (tabId === null || typeof tabId === 'undefined') {
-      return;
+      return Promise.resolve();
     }
-    this.tabPresenter.select(tabId);
+    return this.tabPresenter.select(tabId);
   }
 }
diff --git a/src/background/usecases/TabUseCase.ts b/src/background/usecases/TabUseCase.ts
index d930842..1615333 100644
--- a/src/background/usecases/TabUseCase.ts
+++ b/src/background/usecases/TabUseCase.ts
@@ -2,20 +2,24 @@ import TabPresenter from '../presenters/TabPresenter';
 import BrowserSettingRepository from '../repositories/BrowserSettingRepository';
 
 export default class TabUseCase {
+  private tabPresenter: TabPresenter;
+
+  private browserSettingRepository: BrowserSettingRepository;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
     this.browserSettingRepository = new BrowserSettingRepository();
   }
 
-  async close(force) {
+  async close(force: boolean): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     if (!force && tab.pinned) {
-      return;
+      return Promise.resolve();
     }
-    return this.tabPresenter.remove([tab.id]);
+    return this.tabPresenter.remove([tab.id as number]);
   }
 
-  async closeRight() {
+  async closeRight(): Promise<any> {
     let tabs = await this.tabPresenter.getAll();
     tabs.sort((t1, t2) => t1.index - t2.index);
     let index = tabs.findIndex(t => t.active);
@@ -25,42 +29,42 @@ export default class TabUseCase {
     for (let i = index + 1; i < tabs.length; ++i) {
       let tab = tabs[i];
       if (!tab.pinned) {
-        this.tabPresenter.remove(tab.id);
+        this.tabPresenter.remove([tab.id as number]);
       }
     }
   }
 
-  reopen() {
+  reopen(): Promise<any> {
     return this.tabPresenter.reopen();
   }
 
-  async reload(cache) {
+  async reload(cache: boolean): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.reload(tab.id, cache);
+    return this.tabPresenter.reload(tab.id as number, cache);
   }
 
-  async setPinned(pinned) {
+  async setPinned(pinned: boolean): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.setPinned(tab.id, pinned);
+    return this.tabPresenter.setPinned(tab.id as number, pinned);
   }
 
-  async togglePinned() {
+  async togglePinned(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.setPinned(tab.id, !tab.pinned);
+    return this.tabPresenter.setPinned(tab.id as number, !tab.pinned);
   }
 
-  async duplicate() {
+  async duplicate(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    return this.tabPresenter.duplicate(tab.id);
+    return this.tabPresenter.duplicate(tab.id as number);
   }
 
-  async openPageSource() {
+  async openPageSource(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     let url = 'view-source:' + tab.url;
     return this.tabPresenter.create(url);
   }
 
-  async openHome(newTab) {
+  async openHome(newTab: boolean): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
     let urls = await this.browserSettingRepository.getHomepageUrls();
     if (urls.length === 1 && urls[0] === 'about:home') {
diff --git a/src/background/usecases/VersionUseCase.ts b/src/background/usecases/VersionUseCase.ts
index ed5112b..207f9e2 100644
--- a/src/background/usecases/VersionUseCase.ts
+++ b/src/background/usecases/VersionUseCase.ts
@@ -3,21 +3,25 @@ import TabPresenter from '../presenters/TabPresenter';
 import NotifyPresenter from '../presenters/NotifyPresenter';
 
 export default class VersionUseCase {
+  private tabPresenter: TabPresenter;
+
+  private notifyPresenter: NotifyPresenter;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
     this.notifyPresenter = new NotifyPresenter();
   }
 
-  notify() {
+  notify(): Promise<string> {
     let title = `Vim Vixen ${manifest.version} has been installed`;
     let message = 'Click here to see release notes';
     let url = this.releaseNoteUrl(manifest.version);
-    this.notifyPresenter.notify(title, message, () => {
+    return this.notifyPresenter.notify(title, message, () => {
       this.tabPresenter.create(url);
     });
   }
 
-  releaseNoteUrl(version) {
+  releaseNoteUrl(version?: string): string {
     if (version) {
       return `https://github.com/ueokande/vim-vixen/releases/tag/${version}`;
     }
diff --git a/src/background/usecases/ZoomUseCase.ts b/src/background/usecases/ZoomUseCase.ts
index 692d6d9..661c3cd 100644
--- a/src/background/usecases/ZoomUseCase.ts
+++ b/src/background/usecases/ZoomUseCase.ts
@@ -1,35 +1,39 @@
 import TabPresenter from '../presenters/TabPresenter';
 
-const ZOOM_SETTINGS = [
+const ZOOM_SETTINGS: number[] = [
   0.33, 0.50, 0.66, 0.75, 0.80, 0.90, 1.00,
   1.10, 1.25, 1.50, 1.75, 2.00, 2.50, 3.00
 ];
 
 export default class ZoomUseCase {
+  private tabPresenter: TabPresenter;
+
   constructor() {
     this.tabPresenter = new TabPresenter();
   }
 
-  async zoomIn(tabId) {
+  async zoomIn(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    let current = await this.tabPresenter.getZoom(tab.id);
+    let tabId = tab.id as number;
+    let current = await this.tabPresenter.getZoom(tabId);
     let factor = ZOOM_SETTINGS.find(f => f > current);
     if (factor) {
-      return this.tabPresenter.setZoom(tabId, factor);
+      return this.tabPresenter.setZoom(tabId as number, factor);
     }
   }
 
-  async zoomOut(tabId) {
+  async zoomOut(): Promise<any> {
     let tab = await this.tabPresenter.getCurrent();
-    let current = await this.tabPresenter.getZoom(tab.id);
-    let factor = [].concat(ZOOM_SETTINGS).reverse().find(f => f < current);
+    let tabId = tab.id as number;
+    let current = await this.tabPresenter.getZoom(tabId);
+    let factor = ZOOM_SETTINGS.slice(0).reverse().find(f => f < current);
     if (factor) {
-      return this.tabPresenter.setZoom(tabId, factor);
+      return this.tabPresenter.setZoom(tabId as number, factor);
     }
   }
 
-  zoomNutoral(tabId) {
-    return this.tabPresenter.setZoom(tabId, 1);
+  async zoomNutoral(): Promise<any> {
+    let tab = await this.tabPresenter.getCurrent();
+    return this.tabPresenter.setZoom(tab.id as number, 1);
   }
-
 }
diff --git a/src/background/usecases/filters.ts b/src/background/usecases/filters.ts
index d057dca..44eb56f 100644
--- a/src/background/usecases/filters.ts
+++ b/src/background/usecases/filters.ts
@@ -1,40 +1,42 @@
-const filterHttp = (items) => {
-  let httpsHosts = items.map(x => new URL(x.url))
+type Item = browser.history.HistoryItem;
+
+const filterHttp = (items: Item[]): Item[] => {
+  let httpsHosts = items.map(x => new URL(x.url as string))
     .filter(x => x.protocol === 'https:')
     .map(x => x.host);
-  httpsHosts = new Set(httpsHosts);
+  let hostsSet = new Set(httpsHosts);
 
-  return items.filter((item) => {
-    let url = new URL(item.url);
-    return url.protocol === 'https:' || !httpsHosts.has(url.host);
+  return items.filter((item: Item) => {
+    let url = new URL(item.url as string);
+    return url.protocol === 'https:' || !hostsSet.has(url.host);
   });
 };
 
-const filterBlankTitle = (items) => {
+const filterBlankTitle = (items: Item[]): Item[] => {
   return items.filter(item => item.title && item.title !== '');
 };
 
-const filterByTailingSlash = (items) => {
-  let urls = items.map(item => new URL(item.url));
+const filterByTailingSlash = (items: Item[]): Item[] => {
+  let urls = items.map(item => new URL(item.url as string));
   let simplePaths = urls
     .filter(url => url.hash === '' && url.search === '')
     .map(url => url.origin + url.pathname);
-  simplePaths = new Set(simplePaths);
+  let pathsSet = new Set(simplePaths);
 
   return items.filter((item) => {
-    let url = new URL(item.url);
+    let url = new URL(item.url as string);
     if (url.hash !== '' || url.search !== '' ||
       url.pathname.slice(-1) !== '/') {
       return true;
     }
-    return !simplePaths.has(url.origin + url.pathname.slice(0, -1));
+    return !pathsSet.has(url.origin + url.pathname.slice(0, -1));
   });
 };
 
-const filterByPathname = (items, min) => {
-  let hash = {};
+const filterByPathname = (items: Item[], min: number): Item[] => {
+  let hash: {[key: string]: Item} = {};
   for (let item of items) {
-    let url = new URL(item.url);
+    let url = new URL(item.url as string);
     let pathname = url.origin + url.pathname;
     if (!hash[pathname]) {
       hash[pathname] = item;
@@ -49,10 +51,10 @@ const filterByPathname = (items, min) => {
   return filtered;
 };
 
-const filterByOrigin = (items, min) => {
-  let hash = {};
+const filterByOrigin = (items: Item[], min: number): Item[] => {
+  let hash: {[key: string]: Item} = {};
   for (let item of items) {
-    let origin = new URL(item.url).origin;
+    let origin = new URL(item.url as string).origin;
     if (!hash[origin]) {
       hash[origin] = item;
     } else if (hash[origin].url.length > item.url.length) {
diff --git a/src/background/usecases/parsers.ts b/src/background/usecases/parsers.ts
index 43c8177..3616ac3 100644
--- a/src/background/usecases/parsers.ts
+++ b/src/background/usecases/parsers.ts
@@ -1,4 +1,4 @@
-const mustNumber = (v) => {
+const mustNumber = (v: any): number => {
   let num = Number(v);
   if (isNaN(num)) {
     throw new Error('Not number: ' + v);
@@ -6,8 +6,11 @@ const mustNumber = (v) => {
   return num;
 };
 
-const parseSetOption = (word, types) => {
-  let [key, value] = word.split('=');
+const parseSetOption = (
+  word: string,
+  types: { [key: string]: string },
+): any[] => {
+  let [key, value]: any[] = word.split('=');
   if (value === undefined) {
     value = !key.startsWith('no');
     key = value ? key : key.slice(2);
@@ -26,6 +29,7 @@ const parseSetOption = (word, types) => {
   case 'number': return [key, mustNumber(value)];
   case 'boolean': return [key, value];
   }
+  throw new Error('Unknown property type: ' + type);
 };
 
 export { parseSetOption };
diff --git a/src/content/scrolls.ts b/src/content/scrolls.ts
index f3124a1..bbf2491 100644
--- a/src/content/scrolls.ts
+++ b/src/content/scrolls.ts
@@ -90,16 +90,6 @@ class Scroller {
   }
 }
 
-class RoughtScroller {
-  constructor(element) {
-    this.element = element;
-  }
-
-  scroll(x, y) {
-    this.element.scrollTo(x, y);
-  }
-}
-
 const getScroll = () => {
   let target = scrollTarget();
   return { x: target.scrollLeft, y: target.scrollTop };
diff --git a/test/background/domains/GlobalMark.test.ts b/test/background/domains/GlobalMark.test.ts
deleted file mode 100644
index ed636e9..0000000
--- a/test/background/domains/GlobalMark.test.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import GlobalMark from 'background/domains/GlobalMark';
-
-describe('background/domains/global-mark', () => {
-  describe('constructor and getter', () => {
-    let mark = new GlobalMark(1, 'http://example.com', 10, 30);
-    expect(mark.tabId).to.equal(1);
-    expect(mark.url).to.equal('http://example.com');
-    expect(mark.x).to.equal(10);
-    expect(mark.y).to.equal(30);
-  });
-});
diff --git a/test/background/repositories/Mark.test.ts b/test/background/repositories/Mark.test.ts
index 2a5b099..167e512 100644
--- a/test/background/repositories/Mark.test.ts
+++ b/test/background/repositories/Mark.test.ts
@@ -9,12 +9,11 @@ describe('background/repositories/mark', () => {
   });
 
   it('get and set', async() => {
-    let mark = new GlobalMark(1, 'http://example.com', 10, 30);
+    let mark = { tabId: 1, url: 'http://example.com', x: 10, y: 30 };
 
     repository.setMark('A', mark);
 
     let got = await repository.getMark('A');
-    expect(got).to.be.a('object');
     expect(got.tabId).to.equal(1);
     expect(got.url).to.equal('http://example.com');
     expect(got.x).to.equal(10);
diff --git a/test/background/repositories/Version.ts b/test/background/repositories/Version.ts
deleted file mode 100644
index c7fa88b..0000000
--- a/test/background/repositories/Version.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import VersionRepository from 'background/repositories/Version';
-
-describe("background/repositories/version", () => {
-  let versionRepository;
-
-  beforeEach(() => {
-    versionRepository = new VersionRepository;
-  });
-
-  describe('#get', () => {
-    beforeEach(() => {
-      return browser.storage.local.remove('version');
-    });
-
-    it('loads saved version', async() => {
-      await browser.storage.local.set({ version: '1.2.3' });
-      let version = await this.versionRepository.get();
-      expect(version).to.equal('1.2.3');
-    });
-
-    it('returns undefined if no versions in storage', async() => {
-      let version = await storage.load();
-      expect(version).to.be.a('undefined');
-    });
-  });
-
-  describe('#update', () => {
-    it('saves version string', async() => {
-      await versionRepository.update('2.3.4');
-      let { version } = await browser.storage.local.get('version');
-      expect(version).to.equal('2.3.4');
-    });
-  });
-});
-- 
cgit v1.2.3