Repository: gitify-app/gitify
Pull request #1223 (2024-06-11 13:50:35)

refactor: introduce branded types
Closes https://github.com/gitify-app/gitify/issues/1141

Created the following branded types:

- [X]  `Hostname`
- [X] `Token`
- [X] `ClientSecret`
- [X] `ClientID`
- [X] `AuthCode`
- [x] `URL` (see follow-up question below)

Follow-up question:
While attempting to create the `URL` branded type, I observed it clashes with JavaScript's URL class. There are also different variations of `url` (i.e `thread_url`, `html_url`, `upload_url`, etc) in the project that I'm unsure of how to handle – do I ignore these variations and create the branded type for the occurrences with `url: string`?

setchy: Awesome work @dammy95 - thank you 🙏 

re: `Url` - all of those are full html urls...  Maybe to avoid the conflict with the JavaScript URL class we can name it differently... perhaps `Link` or `WebUrl`.  @afonsojramos @bmulholland - what do you guys think?
bmulholland: Link reads less awkwardly than WebUrl, at least to me. I have no better ideas.
afonsojramos: Yep, agree with the above!
dammy95: Thanks for the feedback @setchy @afonsojramos @bmulholland ⭐ 

Patch:
diff --git a/index.html b/index.html
index 7705d6ee..a3926896 100644
--- a/index.html
+++ b/index.html
@@ -33,18 +33,6 @@
       height: 100%;
     }
 
-    .notification-exit {
-      transform: translate3d(0px, 0, 0);
-      opacity: 1;
-      transition-duration: 250ms;
-      transition-timing-function: cubic-bezier(0.175, 0.665, 0.32, 1), linear;
-    }
-
-    .notification-exit.notification-exit-active {
-      transform: translate3d(350px, 0, 0);
-      opacity: 0;
-    }
-
     #nprogress {
       pointer-events: none;
     }
diff --git a/src/__mocks__/partial-mocks.ts b/src/__mocks__/partial-mocks.ts
index aefbbe9b..2d6023a8 100644
--- a/src/__mocks__/partial-mocks.ts
+++ b/src/__mocks__/partial-mocks.ts
@@ -1,3 +1,4 @@
+import type { Hostname, Link } from '../types';
 import type { Notification, Subject, User } from '../typesGitHub';
 import Constants from '../utils/constants';
 import { mockGitifyUser, mockToken } from './state-mocks';
@@ -9,7 +10,7 @@ export function partialMockNotification(
     account: {
       method: 'Personal Access Token',
       platform: 'GitHub Cloud',
-      hostname: Constants.GITHUB_API_BASE_URL,
+      hostname: Constants.GITHUB_API_BASE_URL as Hostname,
       token: mockToken,
       user: mockGitifyUser,
     },
@@ -22,8 +23,8 @@ export function partialMockNotification(
 export function partialMockUser(login: string): User {
   const mockUser: Partial<User> = {
     login: login,
-    html_url: `https://github.com/${login}`,
-    avatar_url: 'https://avatars.githubusercontent.com/u/583231?v=4',
+    html_url: `https://github.com/${login}` as Link,
+    avatar_url: 'https://avatars.githubusercontent.com/u/583231?v=4' as Link,
     type: 'User',
   };
 
diff --git a/src/__mocks__/state-mocks.ts b/src/__mocks__/state-mocks.ts
index e8828d63..cc2848e6 100644
--- a/src/__mocks__/state-mocks.ts
+++ b/src/__mocks__/state-mocks.ts
@@ -3,16 +3,18 @@ import {
   type AuthState,
   type GitifyState,
   type GitifyUser,
+  type Hostname,
   type SettingsState,
   Theme,
+  type Token,
 } from '../types';
 import type { EnterpriseAccount } from '../utils/auth/types';
 import Constants from '../utils/constants';
 
 export const mockEnterpriseAccounts: EnterpriseAccount[] = [
   {
-    hostname: 'github.gitify.io',
-    token: '1234568790',
+    hostname: 'github.gitify.io' as Hostname,
+    token: '1234568790' as Token,
   },
 ];
 
@@ -25,7 +27,7 @@ export const mockGitifyUser: GitifyUser = {
 export const mockPersonalAccessTokenAccount: Account = {
   platform: 'GitHub Cloud',
   method: 'Personal Access Token',
-  token: 'token-123-456',
+  token: 'token-123-456' as Token,
   hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
   user: mockGitifyUser,
 };
@@ -33,15 +35,15 @@ export const mockPersonalAccessTokenAccount: Account = {
 export const mockOAuthAccount: Account = {
   platform: 'GitHub Enterprise Server',
   method: 'OAuth App',
-  token: '1234568790',
-  hostname: 'github.gitify.io',
+  token: '1234568790' as Token,
+  hostname: 'github.gitify.io' as Hostname,
   user: mockGitifyUser,
 };
 
 export const mockGitHubCloudAccount: Account = {
   platform: 'GitHub Cloud',
   method: 'Personal Access Token',
-  token: 'token-123-456',
+  token: 'token-123-456' as Token,
   hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
   user: mockGitifyUser,
 };
@@ -49,15 +51,15 @@ export const mockGitHubCloudAccount: Account = {
 export const mockGitHubEnterpriseServerAccount: Account = {
   platform: 'GitHub Enterprise Server',
   method: 'Personal Access Token',
-  token: '1234568790',
-  hostname: 'github.gitify.io',
+  token: '1234568790' as Token,
+  hostname: 'github.gitify.io' as Hostname,
   user: mockGitifyUser,
 };
 
 export const mockGitHubAppAccount: Account = {
   platform: 'GitHub Cloud',
   method: 'GitHub App',
-  token: '987654321',
+  token: '987654321' as Token,
   hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
   user: mockGitifyUser,
 };
@@ -66,7 +68,7 @@ export const mockAuth: AuthState = {
   accounts: [mockGitHubCloudAccount, mockGitHubEnterpriseServerAccount],
 };
 
-export const mockToken = 'token-123-456';
+export const mockToken = 'token-123-456' as Token;
 
 export const mockSettings: SettingsState = {
   participating: false,
diff --git a/src/components/fields/Button.tsx b/src/components/fields/Button.tsx
index 3655b553..84960e1e 100644
--- a/src/components/fields/Button.tsx
+++ b/src/components/fields/Button.tsx
@@ -1,5 +1,6 @@
 import type { Icon } from '@primer/octicons-react';
 import type { FC } from 'react';
+import type { Link } from '../../types';
 import { cn } from '../../utils/cn';
 import { openExternalLink } from '../../utils/comms';
 
@@ -9,7 +10,7 @@ export interface IButton {
   className?: string;
   icon?: Icon;
   size?: number;
-  url?: string;
+  url?: Link;
   onClick?: () => void;
   disabled?: boolean;
   type?: 'button' | 'submit';
diff --git a/src/routes/LoginWithOAuthApp.tsx b/src/routes/LoginWithOAuthApp.tsx
index 07f0c9d7..a74334a1 100644
--- a/src/routes/LoginWithOAuthApp.tsx
+++ b/src/routes/LoginWithOAuthApp.tsx
@@ -10,6 +10,7 @@ import { useNavigate } from 'react-router-dom';
 import { Button } from '../components/fields/Button';
 import { FieldInput } from '../components/fields/FieldInput';
 import { AppContext } from '../context/App';
+import type { ClientID, ClientSecret, Hostname, Token } from '../types';
 import type { LoginOAuthAppOptions } from '../utils/auth/types';
 import {
   getNewOAuthAppURL,
@@ -20,9 +21,9 @@ import {
 import Constants from '../utils/constants';
 
 interface IValues {
-  hostname?: string;
-  clientId?: string;
-  clientSecret?: string;
+  hostname?: Hostname;
+  clientId?: ClientID;
+  clientSecret?: ClientSecret;
 }
 
 interface IFormErrors {
@@ -48,7 +49,7 @@ export const validate = (values: IValues): IFormErrors => {
 
   if (!values.clientSecret) {
     errors.clientSecret = 'Required';
-  } else if (!isValidToken(values.clientSecret)) {
+  } else if (!isValidToken(values.clientSecret as unknown as Token)) {
     errors.clientSecret = 'Invalid client secret.';
   }
 
diff --git a/src/routes/LoginWithPersonalAccessToken.tsx b/src/routes/LoginWithPersonalAccessToken.tsx
index 46b85f92..fde80e34 100644
--- a/src/routes/LoginWithPersonalAccessToken.tsx
+++ b/src/routes/LoginWithPersonalAccessToken.tsx
@@ -10,6 +10,7 @@ import { useNavigate } from 'react-router-dom';
 import { Button } from '../components/fields/Button';
 import { FieldInput } from '../components/fields/FieldInput';
 import { AppContext } from '../context/App';
+import type { Hostname, Token } from '../types';
 import type { LoginPersonalAccessTokenOptions } from '../utils/auth/types';
 import {
   getNewTokenURL,
@@ -19,8 +20,8 @@ import {
 import { Constants } from '../utils/constants';
 
 interface IValues {
-  token?: string;
-  hostname?: string;
+  token?: Token;
+  hostname?: Hostname;
 }
 
 interface IFormErrors {
@@ -158,7 +159,7 @@ export const LoginWithPersonalAccessToken: FC = () => {
         <Form
           initialValues={{
             hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
-            token: '',
+            token: '' as Token,
           }}
           onSubmit={login}
           validate={validate}
diff --git a/src/types.ts b/src/types.ts
index b9688f53..7b3d1bbd 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -7,14 +7,16 @@ import type {
   PlatformType,
 } from './utils/auth/types';
 
-export type Status = 'loading' | 'success' | 'error';
+declare const __brand: unique symbol;
+
+type Brand<B> = { [__brand]: B };
 
 export interface AuthState {
   accounts: Account[];
   /**
    * @deprecated This attribute is deprecated and will be removed in a future release.
    */
-  token?: string;
+  token?: Token;
   /**
    * @deprecated This attribute is deprecated and will be removed in a future release.
    */
@@ -25,11 +27,27 @@ export interface AuthState {
   user?: GitifyUser | null;
 }
 
+export type Branded<T, B> = T & Brand<B>;
+
+export type AuthCode = Branded<string, 'AuthCode'>;
+
+export type Token = Branded<string, 'Token'>;
+
+export type ClientID = Branded<string, 'ClientID'>;
+
+export type ClientSecret = Branded<string, 'ClientSecret'>;
+
+export type Hostname = Branded<string, 'Hostname'>;
+
+export type Link = Branded<string, 'WebUrl'>;
+
+export type Status = 'loading' | 'success' | 'error';
+
 export interface Account {
   method: AuthMethod;
   platform: PlatformType;
-  hostname: string;
-  token: string;
+  hostname: Hostname;
+  token: Token;
   user: GitifyUser | null;
 }
 
diff --git a/src/typesGitHub.ts b/src/typesGitHub.ts
index 17f0404f..2fed9d32 100644
--- a/src/typesGitHub.ts
+++ b/src/typesGitHub.ts
@@ -1,4 +1,4 @@
-import type { Account } from './types';
+import type { Account, Link } from './types';
 
 export type Reason =
   | 'approval_requested'
@@ -103,8 +103,8 @@ export interface GitHubNotification {
   last_read_at: string | null;
   subject: Subject;
   repository: Repository;
-  url: string;
-  subscription_url: string;
+  url: Link;
+  subscription_url: Link;
 }
 
 // Note: This is not in the official GitHub API. We add this to make notification interactions easier.
@@ -149,34 +149,34 @@ export interface User {
   login: string;
   id: number;
   node_id: string;
-  avatar_url: string;
-  gravatar_url: string;
-  url: string;
-  html_url: string;
-  followers_url: string;
-  following_url: string;
-  gists_url: string;
-  starred_url: string;
-  subscriptions_url: string;
-  organizations_url: string;
-  repos_url: string;
-  events_url: string;
-  received_events_url: string;
+  avatar_url: Link;
+  gravatar_url: Link;
+  url: Link;
+  html_url: Link;
+  followers_url: Link;
+  following_url: Link;
+  gists_url: Link;
+  starred_url: Link;
+  subscriptions_url: Link;
+  organizations_url: Link;
+  repos_url: Link;
+  events_url: Link;
+  received_events_url: Link;
   type: UserType;
   site_admin: boolean;
 }
 
 export interface SubjectUser {
   login: string;
-  html_url: string;
-  avatar_url: string;
+  html_url: Link;
+  avatar_url: Link;
   type: UserType;
 }
 
 export interface DiscussionAuthor {
   login: string;
-  url: string;
-  avatar_url: string;
+  url: Link;
+  avatar_url: Link;
   type: UserType;
 }
 
@@ -187,65 +187,65 @@ export interface Repository {
   full_name: string;
   private: boolean;
   owner: Owner;
-  html_url: string;
+  html_url: Link;
   description: string;
   fork: boolean;
-  url: string;
-  forks_url: string;
-  keys_url: string;
-  collaborators_url: string;
-  teams_url: string;
-  hooks_url: string;
-  issue_events_url: string;
-  events_url: string;
-  assignees_url: string;
-  branches_url: string;
-  tags_url: string;
-  blobs_url: string;
-  git_tags_url: string;
-  git_refs_url: string;
-  trees_url: string;
-  statuses_url: string;
-  languages_url: string;
-  stargazers_url: string;
-  contributors_url: string;
-  subscribers_url: string;
-  subscription_url: string;
-  commits_url: string;
-  git_commits_url: string;
-  comments_url: string;
-  issue_comment_url: string;
-  contents_url: string;
-  compare_url: string;
-  merges_url: string;
-  archive_url: string;
-  downloads_url: string;
-  issues_url: string;
-  pulls_url: string;
-  milestones_url: string;
-  notifications_url: string;
-  labels_url: string;
-  releases_url: string;
-  deployments_url: string;
+  url: Link;
+  forks_url: Link;
+  keys_url: Link;
+  collaborators_url: Link;
+  teams_url: Link;
+  hooks_url: Link;
+  issue_events_url: Link;
+  events_url: Link;
+  assignees_url: Link;
+  branches_url: Link;
+  tags_url: Link;
+  blobs_url: Link;
+  git_tags_url: Link;
+  git_refs_url: Link;
+  trees_url: Link;
+  statuses_url: Link;
+  languages_url: Link;
+  stargazers_url: Link;
+  contributors_url: Link;
+  subscribers_url: Link;
+  subscription_url: Link;
+  commits_url: Link;
+  git_commits_url: Link;
+  comments_url: Link;
+  issue_comment_url: Link;
+  contents_url: Link;
+  compare_url: Link;
+  merges_url: Link;
+  archive_url: Link;
+  downloads_url: Link;
+  issues_url: Link;
+  pulls_url: Link;
+  milestones_url: Link;
+  notifications_url: Link;
+  labels_url: Link;
+  releases_url: Link;
+  deployments_url: Link;
 }
 
 export interface Owner {
   login: string;
   id: number;
   node_id: string;
-  avatar_url: string;
+  avatar_url: Link;
   gravatar_id: string;
-  url: string;
-  html_url: string;
-  followers_url: string;
-  following_url: string;
-  gists_url: string;
-  starred_url: string;
-  subscriptions_url: string;
-  organizations_url: string;
-  repos_url: string;
-  events_url: string;
-  received_events_url: string;
+  url: Link;
+  html_url: Link;
+  followers_url: Link;
+  following_url: Link;
+  gists_url: Link;
+  starred_url: Link;
+  subscriptions_url: Link;
+  organizations_url: Link;
+  repos_url: Link;
+  events_url: Link;
+  received_events_url: Link;
   type: string;
   site_admin: boolean;
 }
@@ -254,8 +254,8 @@ export type Subject = GitHubSubject & GitifySubject;
 
 interface GitHubSubject {
   title: string;
-  url: string | null;
-  latest_comment_url: string | null;
+  url: Link | null;
+  latest_comment_url: Link | null;
   type: SubjectType;
 }
 
@@ -271,13 +271,13 @@ export interface GitifySubject {
 }
 
 export interface PullRequest {
-  url: string;
+  url: Link;
   id: number;
   node_id: string;
-  html_url: string;
-  diff_url: string;
-  patch_url: string;
-  issue_url: string;
+  html_url: Link;
+  diff_url: Link;
+  patch_url: Link;
+  issue_url: Link;
   number: number;
   state: PullRequestStateType;
   locked: boolean;
@@ -292,11 +292,11 @@ export interface PullRequest {
   labels: Labels[];
   milestone: Milestone | null;
   draft: boolean;
-  commits_url: string;
-  review_comments_url: string;
-  review_comment_url: string;
-  comments_url: string;
-  statuses_url: string;
+  commits_url: Link;
+  review_comments_url: Link;
+  review_comment_url: Link;
+  comments_url: Link;
+  statuses_url: Link;
   author_association: string;
   merged: boolean;
   mergeable: boolean;
@@ -318,7 +318,7 @@ export interface GitifyPullRequestReview {
 export interface Labels {
   id: number;
   node_id: string;
-  url: string;
+  url: Link;
   name: string;
   color: string;
   default: boolean;
@@ -331,8 +331,8 @@ export interface PullRequestReview {
   user: User;
   body: string;
   state: PullRequestReviewState;
-  html_url: string;
-  pull_request_url: string;
+  html_url: Link;
+  pull_request_url: Link;
   author_association: PullRequestReviewAuthorAssociation;
   submitted_at: string;
   commit_id: string;
@@ -347,9 +347,9 @@ export interface Commit {
     message: string;
     tree: {
       sha: string;
-      url: string;
+      url: Link;
     };
-    url: string;
+    url: Link;
     comment_count: number;
     verification: {
       verified: boolean;
@@ -358,9 +358,9 @@ export interface Commit {
       payload: string | null;
     };
   };
-  url: string;
-  html_url: string;
-  comments_url: string;
+  url: Link;
+  html_url: Link;
+  comments_url: Link;
   author: User;
   committer: User;
   parents: CommitParent[];
@@ -380,8 +380,8 @@ interface CommitUser {
 
 interface CommitParent {
   sha: string;
-  url: string;
-  html_url: string;
+  url: Link;
+  html_url: Link;
 }
 
 interface CommitFiles {
@@ -391,16 +391,16 @@ interface CommitFiles {
   additions: number;
   deletions: number;
   changes: number;
-  blob_url: string;
-  raw_url: string;
-  contents_url: string;
+  blob_url: Link;
+  raw_url: Link;
+  contents_url: Link;
   patch: string;
 }
 
 export interface CommitComment {
-  url: string;
-  html_url: string;
-  issue_url: string;
+  url: Link;
+  html_url: Link;
+  issue_url: Link;
   id: number;
   node_id: string;
   user: User;
@@ -410,12 +410,12 @@ export interface CommitComment {
 }
 
 export interface Issue {
-  url: string;
-  repository_url: string;
-  labels_url: string;
-  comments_url: string;
-  events_url: string;
-  html_url: string;
+  url: Link;
+  repository_url: Link;
+  labels_url: Link;
+  comments_url: Link;
+  events_url: Link;
+  html_url: Link;
   id: number;
   node_id: string;
   number: number;
@@ -435,9 +435,9 @@ export interface Issue {
 }
 
 export interface IssueOrPullRequestComment {
-  url: string;
-  html_url: string;
-  issue_url: string;
+  url: Link;
+  html_url: Link;
+  issue_url: Link;
   id: number;
   node_id: string;
   user: User;
@@ -447,9 +447,9 @@ export interface IssueOrPullRequestComment {
 }
 
 export interface Milestone {
-  url: string;
-  html_url: string;
-  labels_url: string;
+  url: Link;
+  html_url: Link;
+  labels_url: Link;
   id: number;
   node_id: string;
   number: number;
@@ -468,10 +468,10 @@ export interface Milestone {
 type MilestoneStateType = 'open' | 'closed';
 
 export interface Release {
-  url: string;
-  assets_url: string;
-  upload_url: string;
-  html_url: string;
+  url: Link;
+  assets_url: Link;
+  upload_url: Link;
+  html_url: Link;
   id: number;
   author: User;
   node_id: string;
@@ -497,7 +497,7 @@ export interface Discussion {
   title: string;
   stateReason: DiscussionStateType;
   isAnswered: boolean;
-  url: string;
+  url: Link;
   author: DiscussionAuthor;
   comments: DiscussionComments;
   labels: DiscussionLabels | null;
@@ -541,7 +541,7 @@ export interface WorkflowRunAttributes {
 
 export interface GitHubRESTError {
   message: string;
-  documentation_url: string;
+  documentation_url: Link;
 }
 
 export interface NotificationThreadSubscription {
@@ -549,6 +549,6 @@ export interface NotificationThreadSubscription {
   ignored: boolean;
   reason: string | null;
   created_at: string;
-  url: string;
-  thread_url: string;
+  url: Link;
+  thread_url: Link;
 }
diff --git a/src/utils/api/__mocks__/response-mocks.ts b/src/utils/api/__mocks__/response-mocks.ts
index 06e438f3..74097fb3 100644
--- a/src/utils/api/__mocks__/response-mocks.ts
+++ b/src/utils/api/__mocks__/response-mocks.ts
@@ -2,6 +2,7 @@ import {
   mockGitHubCloudAccount,
   mockGitHubEnterpriseServerAccount,
 } from '../../../__mocks__/state-mocks';
+import type { Link } from '../../../types';
 import type {
   Discussion,
   DiscussionAuthor,
@@ -17,19 +18,23 @@ export const mockNotificationUser: User = {
   login: 'octocat',
   id: 123456789,
   node_id: 'MDQ6VXNlcjE=',
-  avatar_url: 'https://avatars.githubusercontent.com/u/583231?v=4',
-  gravatar_url: '',
-  url: 'https://api.github.com/users/octocat',
-  html_url: 'https://github.com/octocat',
-  followers_url: 'https://api.github.com/users/octocat/followers',
-  following_url: 'https://api.github.com/users/octocat/following{/other_user}',
-  gists_url: 'https://api.github.com/users/octocat/gists{/gist_id}',
-  starred_url: 'https://api.github.com/users/octocat/starred{/owner}{/repo}',
-  subscriptions_url: 'https://api.github.com/users/octocat/subscriptions',
-  organizations_url: 'https://api.github.com/users/octocat/orgs',
-  repos_url: 'https://api.github.com/users/octocat/repos',
-  events_url: 'https://api.github.com/users/octocat/events{/privacy}',
-  received_events_url: 'https://api.github.com/users/octocat/received_events',
+  avatar_url: 'https://avatars.githubusercontent.com/u/583231?v=4' as Link,
+  gravatar_url: '' as Link,
+  url: 'https://api.github.com/users/octocat' as Link,
+  html_url: 'https://github.com/octocat' as Link,
+  followers_url: 'https://api.github.com/users/octocat/followers' as Link,
+  following_url:
+    'https://api.github.com/users/octocat/following{/other_user}' as Link,
+  gists_url: 'https://api.github.com/users/octocat/gists{/gist_id}' as Link,
+  starred_url:
+    'https://api.github.com/users/octocat/starred{/owner}{/repo}' as Link,
+  subscriptions_url:
+    'https://api.github.com/users/octocat/subscriptions' as Link,
+  organizations_url: 'https://api.github.com/users/octocat/orgs' as Link,
+  repos_url: 'https://api.github.com/users/octocat/repos' as Link,
+  events_url: 'https://api.github.com/users/octocat/events{/privacy}' as Link,
+  received_events_url:
+    'https://api.github.com/users/octocat/received_events' as Link,
   type: 'User',
   site_admin: false,
 };
@@ -47,16 +52,16 @@ export const mockGitHubNotifications: Notification[] = [
     last_read_at: '2017-05-20T17:06:51Z',
     subject: {
       title: 'I am a robot and this is a test!',
-      url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1',
+      url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1' as Link,
       latest_comment_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302888448',
+        'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302888448' as Link,
       type: 'Issue',
       state: 'open',
       user: {
         login: 'gitify-app',
-        html_url: 'https://github.com/gitify-app',
+        html_url: 'https://github.com/gitify-app' as Link,
         avatar_url:
-          'https://avatars.githubusercontent.com/u/133795385?s=200&v=4',
+          'https://avatars.githubusercontent.com/u/133795385?s=200&v=4' as Link,
         type: 'User',
       },
       reviews: [
@@ -79,29 +84,33 @@ export const mockGitHubNotifications: Notification[] = [
       node_id: 'MDEwOlJlcG9zaXRvcnkzNjAyOTcwNg==',
       name: 'notifications-test',
       full_name: 'gitify-app/notifications-test',
-      url: 'https://api.github.com/gitify-app/notifications-test',
+      url: 'https://api.github.com/gitify-app/notifications-test' as Link,
       owner: {
         login: 'gitify-app',
         id: 6333409,
         node_id: 'MDQ6VXNlcjYzMzM0MDk=',
         avatar_url:
-          'https://avatars.githubusercontent.com/u/133795385?s=200&v=4',
+          'https://avatars.githubusercontent.com/u/133795385?s=200&v=4' as Link,
         gravatar_id: '',
-        url: 'https://api.github.com/users/gitify-app',
-        html_url: 'https://github.com/gitify-app',
-        followers_url: 'https://api.github.com/users/gitify-app/followers',
+        url: 'https://api.github.com/users/gitify-app' as Link,
+        html_url: 'https://github.com/gitify-app' as Link,
+        followers_url:
+          'https://api.github.com/users/gitify-app/followers' as Link,
         following_url:
-          'https://api.github.com/users/gitify-app/following{/other_user}',
-        gists_url: 'https://api.github.com/users/gitify-app/gists{/gist_id}',
+          'https://api.github.com/users/gitify-app/following{/other_user}' as Link,
+        gists_url:
+          'https://api.github.com/users/gitify-app/gists{/gist_id}' as Link,
         starred_url:
-          'https://api.github.com/users/gitify-app/starred{/owner}{/repo}',
+          'https://api.github.com/users/gitify-app/starred{/owner}{/repo}' as Link,
         subscriptions_url:
-          'https://api.github.com/users/gitify-app/subscriptions',
-        organizations_url: 'https://api.github.com/users/gitify-app/orgs',
-        repos_url: 'https://api.github.com/users/gitify-app/repos',
-        events_url: 'https://api.github.com/users/gitify-app/events{/privacy}',
+          'https://api.github.com/users/gitify-app/subscriptions' as Link,
+        organizations_url:
+          'https://api.github.com/users/gitify-app/orgs' as Link,
+        repos_url: 'https://api.github.com/users/gitify-app/repos' as Link,
+        events_url:
+          'https://api.github.com/users/gitify-app/events{/privacy}' as Link,
         received_events_url:
-          'https://api.github.com/users/gitify-app/received_events',
+          'https://api.github.com/users/gitify-app/received_events' as Link,
         type: 'User',
         site_admin: false,
       },
@@ -109,82 +118,82 @@ export const mockGitHubNotifications: Notification[] = [
       description: 'Test Repository',
       fork: false,
       archive_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/{archive_format}{/ref}',
+        'https://api.github.com/repos/gitify-app/notifications-test/{archive_format}{/ref}' as Link,
       assignees_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/assignees{/user}',
+        'https://api.github.com/repos/gitify-app/notifications-test/assignees{/user}' as Link,
       blobs_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/git/blobs{/sha}',
+        'https://api.github.com/repos/gitify-app/notifications-test/git/blobs{/sha}' as Link,
       branches_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/branches{/branch}',
+        'https://api.github.com/repos/gitify-app/notifications-test/branches{/branch}' as Link,
       collaborators_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/collaborators{/collaborator}',
+        'https://api.github.com/repos/gitify-app/notifications-test/collaborators{/collaborator}' as Link,
       comments_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/comments{/number}',
+        'https://api.github.com/repos/gitify-app/notifications-test/comments{/number}' as Link,
       commits_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/commits{/sha}',
+        'https://api.github.com/repos/gitify-app/notifications-test/commits{/sha}' as Link,
       compare_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/compare/{base}...{head}',
+        'https://api.github.com/repos/gitify-app/notifications-test/compare/{base}...{head}' as Link,
       contents_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/contents/{+path}',
+        'https://api.github.com/repos/gitify-app/notifications-test/contents/{+path}' as Link,
       contributors_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/contributors',
+        'https://api.github.com/repos/gitify-app/notifications-test/contributors' as Link,
       deployments_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/deployments',
+        'https://api.github.com/repos/gitify-app/notifications-test/deployments' as Link,
       downloads_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/downloads',
+        'https://api.github.com/repos/gitify-app/notifications-test/downloads' as Link,
       events_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/events',
+        'https://api.github.com/repos/gitify-app/notifications-test/events' as Link,
       forks_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/forks',
+        'https://api.github.com/repos/gitify-app/notifications-test/forks' as Link,
       git_commits_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/git/commits{/sha}',
+        'https://api.github.com/repos/gitify-app/notifications-test/git/commits{/sha}' as Link,
       git_refs_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/git/refs{/sha}',
+        'https://api.github.com/repos/gitify-app/notifications-test/git/refs{/sha}' as Link,
       git_tags_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/git/tags{/sha}',
+        'https://api.github.com/repos/gitify-app/notifications-test/git/tags{/sha}' as Link,
       hooks_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/hooks',
-      html_url: 'https://github.com/gitify-app/notifications-test',
+        'https://api.github.com/repos/gitify-app/notifications-test/hooks' as Link,
+      html_url: 'https://github.com/gitify-app/notifications-test' as Link,
       issue_comment_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/issues/comments{/number}',
+        'https://api.github.com/repos/gitify-app/notifications-test/issues/comments{/number}' as Link,
       issue_events_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/issues/events{/number}',
+        'https://api.github.com/repos/gitify-app/notifications-test/issues/events{/number}' as Link,
       issues_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/issues{/number}',
+        'https://api.github.com/repos/gitify-app/notifications-test/issues{/number}' as Link,
       keys_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/keys{/key_id}',
+        'https://api.github.com/repos/gitify-app/notifications-test/keys{/key_id}' as Link,
       labels_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/labels{/name}',
+        'https://api.github.com/repos/gitify-app/notifications-test/labels{/name}' as Link,
       languages_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/languages',
+        'https://api.github.com/repos/gitify-app/notifications-test/languages' as Link,
       merges_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/merges',
+        'https://api.github.com/repos/gitify-app/notifications-test/merges' as Link,
       milestones_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/milestones{/number}',
+        'https://api.github.com/repos/gitify-app/notifications-test/milestones{/number}' as Link,
       notifications_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/notifications{?since,all,participating}',
+        'https://api.github.com/repos/gitify-app/notifications-test/notifications{?since,all,participating}' as Link,
       pulls_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/pulls{/number}',
+        'https://api.github.com/repos/gitify-app/notifications-test/pulls{/number}' as Link,
       releases_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/releases{/id}',
+        'https://api.github.com/repos/gitify-app/notifications-test/releases{/id}' as Link,
       stargazers_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/stargazers',
+        'https://api.github.com/repos/gitify-app/notifications-test/stargazers' as Link,
       statuses_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/statuses/{sha}',
+        'https://api.github.com/repos/gitify-app/notifications-test/statuses/{sha}' as Link,
       subscribers_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/subscribers',
+        'https://api.github.com/repos/gitify-app/notifications-test/subscribers' as Link,
       subscription_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/subscription',
+        'https://api.github.com/repos/gitify-app/notifications-test/subscription' as Link,
       tags_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/tags',
+        'https://api.github.com/repos/gitify-app/notifications-test/tags' as Link,
       teams_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/teams',
+        'https://api.github.com/repos/gitify-app/notifications-test/teams' as Link,
       trees_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/git/trees{/sha}',
+        'https://api.github.com/repos/gitify-app/notifications-test/git/trees{/sha}' as Link,
     },
-    url: 'https://api.github.com/notifications/threads/138661096',
+    url: 'https://api.github.com/notifications/threads/138661096' as Link,
     subscription_url:
-      'https://api.github.com/notifications/threads/138661096/subscription',
+      'https://api.github.com/notifications/threads/138661096/subscription' as Link,
   },
   {
     account: mockGitHubCloudAccount,
@@ -195,9 +204,9 @@ export const mockGitHubNotifications: Notification[] = [
     last_read_at: '2017-05-20T16:59:03Z',
     subject: {
       title: 'Improve the UI',
-      url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/4',
+      url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/4' as Link,
       latest_comment_url:
-        'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302885965',
+        'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302885965' as Link,
       type: 'Issue',
       reviews: null,
     },
@@ -209,23 +218,27 @@ export const mockGitHubNotifications: Notification[] = [
         login: 'gitify-app',
         id: 6333409,
         avatar_url:
-          'https://avatars.githubusercontent.com/u/133795385?s=200&v=4',
+          'https://avatars.githubusercontent.com/u/133795385?s=200&v=4' as Link,
         gravatar_id: '',
-        url: 'https://api.github.com/users/gitify-app',
-        html_url: 'https://github.com/gitify-app',
-        followers_url: 'https://api.github.com/users/gitify-app/followers',
+        url: 'https://api.github.com/users/gitify-app' as Link,
+        html_url: 'https://github.com/gitify-app' as Link,
+        followers_url:
+          'https://api.github.com/users/gitify-app/followers' as Link,
         following_url:
-          'https://api.github.com/users/gitify-app/following{/other_user}',
-        gists_url: 'https://api.github.com/users/gitify-app/gists{/gist_id}',
+          'https://api.github.com/users/gitify-app/following{/other_user}' as Link,
+        gists_url:
+          'https://api.github.com/users/gitify-app/gists{/gist_id}' as Link,
         starred_url:
-          'https://api.github.com/users/gitify-app/starred{/owner}{/repo}',
+          'https://api.github.com/users/gitify-app/starred{/owner}{/repo}' as Link,
         subscriptions_url:
-          'https://api.github.com/users/gitify-app/subscriptions',
-        organizations_url: 'https://api.github.com/users/gitify-app/orgs',
-        repos_url: 'https://api.github.com/users/gitify-app/repos',
-        events_url: 'https://api.github.com/users/gitify-app/events{/privacy}',
+          'https://api.github.com/users/gitify-app/subscriptions' as Link,
+        organizations_url:
+          'https://api.github.com/users/gitify-app/orgs' as Link,
+        repos_url: 'https://api.github.com/users/gitify-app/repos' as Link,
+        events_url:
+          'https://api.github.com/users/gitify-app/events{/privacy}' as Link,
         received_events_url:
-          'https://api.github.com/users/gitify-app/received_events',
+          'https://api.github.com/users/gitify-app/received_events' as Link,
         type: 'User',
         site_admin: false,
       },
@@ -235,9 +248,9 @@ export const mockGitHubNotifications: Notification[] = [
       fork: false,
       // Removed the rest of the properties
     } as unknown as Repository,
-    url: 'https://api.github.com/notifications/threads/148827438',
+    url: 'https://api.github.com/notifications/threads/148827438' as Link,
     subscription_url:
-      'https://api.github.com/notifications/threads/148827438/subscription',
+      'https://api.github.com/notifications/threads/148827438/subscription' as Link,
   },
 ];
 
@@ -254,9 +267,9 @@ export const mockEnterpriseNotifications: Notification[] = [
     last_read_at: null,
     subject: {
       title: 'Release 0.0.1',
-      url: 'https://github.gitify.io/api/v3/repos/myorg/notifications-test/releases/3',
+      url: 'https://github.gitify.io/api/v3/repos/myorg/notifications-test/releases/3' as Link,
       latest_comment_url:
-        'https://github.gitify.io/api/v3/repos/myorg/notifications-test/releases/3',
+        'https://github.gitify.io/api/v3/repos/myorg/notifications-test/releases/3' as Link,
       type: 'Release',
       reviews: null,
     },
@@ -267,37 +280,39 @@ export const mockEnterpriseNotifications: Notification[] = [
       owner: {
         login: 'myorg',
         id: 4,
-        avatar_url: 'https://github.gitify.io/avatars/u/4?',
+        avatar_url: 'https://github.gitify.io/avatars/u/4?' as Link,
         gravatar_id: '',
         url: 'https://github.gitify.io/api/v3/users/myorg',
-        html_url: 'https://github.gitify.io/myorg',
-        followers_url: 'https://github.gitify.io/api/v3/users/myorg/followers',
+        html_url: 'https://github.gitify.io/myorg' as Link,
+        followers_url:
+          'https://github.gitify.io/api/v3/users/myorg/followers' as Link,
         following_url:
-          'https://github.gitify.io/api/v3/users/myorg/following{/other_user}',
+          'https://github.gitify.io/api/v3/users/myorg/following{/other_user}' as Link,
         gists_url:
-          'https://github.gitify.io/api/v3/users/myorg/gists{/gist_id}',
+          'https://github.gitify.io/api/v3/users/myorg/gists{/gist_id}' as Link,
         starred_url:
-          'https://github.gitify.io/api/v3/users/myorg/starred{/owner}{/repo}',
+          'https://github.gitify.io/api/v3/users/myorg/starred{/owner}{/repo}' as Link,
         subscriptions_url:
-          'https://github.gitify.io/api/v3/users/myorg/subscriptions',
-        organizations_url: 'https://github.gitify.io/api/v3/users/myorg/orgs',
-        repos_url: 'https://github.gitify.io/api/v3/users/myorg/repos',
+          'https://github.gitify.io/api/v3/users/myorg/subscriptions' as Link,
+        organizations_url:
+          'https://github.gitify.io/api/v3/users/myorg/orgs' as Link,
+        repos_url: 'https://github.gitify.io/api/v3/users/myorg/repos' as Link,
         events_url:
-          'https://github.gitify.io/api/v3/users/myorg/events{/privacy}',
+          'https://github.gitify.io/api/v3/users/myorg/events{/privacy}' as Link,
         received_events_url:
-          'https://github.gitify.io/api/v3/users/myorg/received_events',
+          'https://github.gitify.io/api/v3/users/myorg/received_events' as Link,
         type: 'Organization',
         site_admin: false,
       },
       private: true,
-      html_url: 'https://github.gitify.io/myorg/notifications-test',
+      html_url: 'https://github.gitify.io/myorg/notifications-test' as Link,
       description: null,
       fork: false,
       // Removed the rest of the properties
     } as unknown as Repository,
-    url: 'https://github.gitify.io/api/v3/notifications/threads/4',
+    url: 'https://github.gitify.io/api/v3/notifications/threads/4' as Link,
     subscription_url:
-      'https://github.gitify.io/api/v3/notifications/threads/4/subscription',
+      'https://github.gitify.io/api/v3/notifications/threads/4/subscription' as Link,
   },
   {
     account: mockGitHubEnterpriseServerAccount,
@@ -308,9 +323,9 @@ export const mockEnterpriseNotifications: Notification[] = [
     last_read_at: '2017-05-20T14:20:55Z',
     subject: {
       title: 'Bump Version',
-      url: 'https://github.gitify.io/api/v3/repos/myorg/notifications-test/pulls/4',
+      url: 'https://github.gitify.io/api/v3/repos/myorg/notifications-test/pulls/4' as Link,
       latest_comment_url:
-        'https://github.gitify.io/api/v3/repos/myorg/notifications-test/issues/comments/21',
+        'https://github.gitify.io/api/v3/repos/myorg/notifications-test/issues/comments/21' as Link,
       type: 'PullRequest',
       reviews: null,
     },
@@ -321,51 +336,53 @@ export const mockEnterpriseNotifications: Notification[] = [
       owner: {
         login: 'myorg',
         id: 4,
-        avatar_url: 'https://github.gitify.io/avatars/u/4?',
+        avatar_url: 'https://github.gitify.io/avatars/u/4?' as Link,
         gravatar_id: '',
-        url: 'https://github.gitify.io/api/v3/users/myorg',
-        html_url: 'https://github.gitify.io/myorg',
-        followers_url: 'https://github.gitify.io/api/v3/users/myorg/followers',
+        url: 'https://github.gitify.io/api/v3/users/myorg' as Link,
+        html_url: 'https://github.gitify.io/myorg' as Link,
+        followers_url:
+          'https://github.gitify.io/api/v3/users/myorg/followers' as Link,
         following_url:
-          'https://github.gitify.io/api/v3/users/myorg/following{/other_user}',
+          'https://github.gitify.io/api/v3/users/myorg/following{/other_user}' as Link,
         gists_url:
-          'https://github.gitify.io/api/v3/users/myorg/gists{/gist_id}',
+          'https://github.gitify.io/api/v3/users/myorg/gists{/gist_id}' as Link,
         starred_url:
-          'https://github.gitify.io/api/v3/users/myorg/starred{/owner}{/repo}',
+          'https://github.gitify.io/api/v3/users/myorg/starred{/owner}{/repo}' as Link,
         subscriptions_url:
-          'https://github.gitify.io/api/v3/users/myorg/subscriptions',
-        organizations_url: 'https://github.gitify.io/api/v3/users/myorg/orgs',
-        repos_url: 'https://github.gitify.io/api/v3/users/myorg/repos',
+          'https://github.gitify.io/api/v3/users/myorg/subscriptions' as Link,
+        organizations_url:
+          'https://github.gitify.io/api/v3/users/myorg/orgs' as Link,
+        repos_url: 'https://github.gitify.io/api/v3/users/myorg/repos' as Link,
         events_url:
-          'https://github.gitify.io/api/v3/users/myorg/events{/privacy}',
+          'https://github.gitify.io/api/v3/users/myorg/events{/privacy}' as Link,
         received_events_url:
-          'https://github.gitify.io/api/v3/users/myorg/received_events',
+          'https://github.gitify.io/api/v3/users/myorg/received_events' as Link,
         type: 'Organization',
         site_admin: false,
       },
       private: true,
-      html_url: 'https://github.gitify.io/myorg/notifications-test',
+      html_url: 'https://github.gitify.io/myorg/notifications-test' as Link,
       description: null,
       fork: false,
       // Removed the rest of the properties
     } as unknown as Repository,
-    url: 'https://github.gitify.io/api/v3/notifications/threads/3',
+    url: 'https://github.gitify.io/api/v3/notifications/threads/3' as Link,
     subscription_url:
-      'https://github.gitify.io/api/v3/notifications/threads/3/subscription',
+      'https://github.gitify.io/api/v3/notifications/threads/3/subscription' as Link,
   },
 ];
 
 const mockDiscussionAuthor: DiscussionAuthor = {
   login: 'comment-user',
-  url: 'https://github.com/comment-user',
-  avatar_url: 'https://avatars.githubusercontent.com/u/123456789?v=4',
+  url: 'https://github.com/comment-user' as Link,
+  avatar_url: 'https://avatars.githubusercontent.com/u/123456789?v=4' as Link,
   type: 'User',
 };
 
 const mockDiscussionReplier: DiscussionAuthor = {
   login: 'reply-user',
-  url: 'https://github.com/reply-user',
-  avatar_url: 'https://avatars.githubusercontent.com/u/123456789?v=4',
+  url: 'https://github.com/reply-user' as Link,
+  avatar_url: 'https://avatars.githubusercontent.com/u/123456789?v=4' as Link,
   type: 'User',
 };
 
@@ -405,11 +422,12 @@ export const mockGraphQLResponse: GraphQLSearch<Discussion> = {
           title: '1.16.0',
           isAnswered: false,
           stateReason: 'OPEN',
-          url: 'https://github.com/gitify-app/notifications-test/discussions/612',
+          url: 'https://github.com/gitify-app/notifications-test/discussions/612' as Link,
           author: {
             login: 'discussion-creator',
-            url: 'https://github.com/discussion-creator',
-            avatar_url: 'https://avatars.githubusercontent.com/u/123456789?v=4',
+            url: 'https://github.com/discussion-creator' as Link,
+            avatar_url:
+              'https://avatars.githubusercontent.com/u/123456789?v=4' as Link,
             type: 'User',
           },
           comments: mockDiscussionComments,
diff --git a/src/utils/api/client.ts b/src/utils/api/client.ts
index 3c74a8bd..daf0a410 100644
--- a/src/utils/api/client.ts
+++ b/src/utils/api/client.ts
@@ -1,6 +1,12 @@
 import type { AxiosPromise } from 'axios';
 import { print } from 'graphql/language/printer';
-import type { Account, SettingsState } from '../../types';
+import type {
+  Account,
+  Hostname,
+  Link,
+  SettingsState,
+  Token,
+} from '../../types';
 import type {
   Commit,
   CommitComment,
@@ -26,24 +32,24 @@ import { getGitHubAPIBaseUrl, getGitHubGraphQLUrl } from './utils';
  * Endpoint documentation: https://docs.github.com/en/rest/users/users#get-the-authenticated-user
  */
 export function getAuthenticatedUser(
-  hostname: string,
-  token: string,
+  hostname: Hostname,
+  token: Token,
 ): AxiosPromise<UserDetails> {
   const url = getGitHubAPIBaseUrl(hostname);
   url.pathname += 'user';
 
-  return apiRequestAuth(url.toString(), 'GET', token);
+  return apiRequestAuth(url.toString() as Link, 'GET', token);
 }
 
 //
 export function headNotifications(
-  hostname: string,
-  token: string,
+  hostname: Hostname,
+  token: Token,
 ): AxiosPromise<void> {
   const url = getGitHubAPIBaseUrl(hostname);
   url.pathname += 'notifications';
 
-  return apiRequestAuth(url.toString(), 'HEAD', token);
+  return apiRequestAuth(url.toString() as Link, 'HEAD', token);
 }
 
 /**
@@ -59,7 +65,7 @@ export function listNotificationsForAuthenticatedUser(
   url.pathname += 'notifications';
   url.searchParams.append('participating', String(settings.participating));
 
-  return apiRequestAuth(url.toString(), 'GET', account.token);
+  return apiRequestAuth(url.toString() as Link, 'GET', account.token);
 }
 
 /**
@@ -70,13 +76,13 @@ export function listNotificationsForAuthenticatedUser(
  */
 export function markNotificationThreadAsRead(
   threadId: string,
-  hostname: string,
-  token: string,
+  hostname: Hostname,
+  token: Token,
 ): AxiosPromise<void> {
   const url = getGitHubAPIBaseUrl(hostname);
   url.pathname += `notifications/threads/${threadId}`;
 
-  return apiRequestAuth(url.toString(), 'PATCH', token, {});
+  return apiRequestAuth(url.toString() as Link, 'PATCH', token, {});
 }
 
 /**
@@ -87,13 +93,13 @@ export function markNotificationThreadAsRead(
  */
 export function markNotificationThreadAsDone(
   threadId: string,
-  hostname: string,
-  token: string,
+  hostname: Hostname,
+  token: Token,
 ): AxiosPromise<void> {
   const url = getGitHubAPIBaseUrl(hostname);
   url.pathname += `notifications/threads/${threadId}`;
 
-  return apiRequestAuth(url.toString(), 'DELETE', token, {});
+  return apiRequestAuth(url.toString() as Link, 'DELETE', token, {});
 }
 
 /**
@@ -103,13 +109,15 @@ export function markNotificationThreadAsDone(
  */
 export function ignoreNotificationThreadSubscription(
   threadId: string,
-  hostname: string,
-  token: string,
+  hostname: Hostname,
+  token: Token,
 ): AxiosPromise<NotificationThreadSubscription> {
   const url = getGitHubAPIBaseUrl(hostname);
   url.pathname += `notifications/threads/${threadId}/subscription`;
 
-  return apiRequestAuth(url.toString(), 'PUT', token, { ignored: true });
+  return apiRequestAuth(url.toString() as Link, 'PUT', token, {
+    ignored: true,
+  });
 }
 
 /**
@@ -122,13 +130,13 @@ export function ignoreNotificationThreadSubscription(
  */
 export function markRepositoryNotificationsAsRead(
   repoSlug: string,
-  hostname: string,
-  token: string,
+  hostname: Hostname,
+  token: Token,
 ): AxiosPromise<void> {
   const url = getGitHubAPIBaseUrl(hostname);
   url.pathname += `repos/${repoSlug}/notifications`;
 
-  return apiRequestAuth(url.toString(), 'PUT', token, {});
+  return apiRequestAuth(url.toString() as Link, 'PUT', token, {});
 }
 
 /**
@@ -136,7 +144,7 @@ export function markRepositoryNotificationsAsRead(
  *
  * Endpoint documentation: https://docs.github.com/en/rest/commits/commits#get-a-commit
  */
-export function getCommit(url: string, token: string): AxiosPromise<Commit> {
+export function getCommit(url: Link, token: Token): AxiosPromise<Commit> {
   return apiRequestAuth(url, 'GET', token);
 }
 
@@ -147,8 +155,8 @@ export function getCommit(url: string, token: string): AxiosPromise<Commit> {
 
  */
 export function getCommitComment(
-  url: string,
-  token: string,
+  url: Link,
+  token: Token,
 ): AxiosPromise<CommitComment> {
   return apiRequestAuth(url, 'GET', token);
 }
@@ -158,7 +166,7 @@ export function getCommitComment(
  *
  * Endpoint documentation: https://docs.github.com/en/rest/issues/issues#get-an-issue
  */
-export function getIssue(url: string, token: string): AxiosPromise<Issue> {
+export function getIssue(url: Link, token: Token): AxiosPromise<Issue> {
   return apiRequestAuth(url, 'GET', token);
 }
 
@@ -169,8 +177,8 @@ export function getIssue(url: string, token: string): AxiosPromise<Issue> {
  * Endpoint documentation: https://docs.github.com/en/rest/issues/comments#get-an-issue-comment
  */
 export function getIssueOrPullRequestComment(
-  url: string,
-  token: string,
+  url: Link,
+  token: Token,
 ): AxiosPromise<IssueOrPullRequestComment> {
   return apiRequestAuth(url, 'GET', token);
 }
@@ -181,8 +189,8 @@ export function getIssueOrPullRequestComment(
  * Endpoint documentation: https://docs.github.com/en/rest/pulls/pulls#get-a-pull-request
  */
 export function getPullRequest(
-  url: string,
-  token: string,
+  url: Link,
+  token: Token,
 ): AxiosPromise<PullRequest> {
   return apiRequestAuth(url, 'GET', token);
 }
@@ -193,8 +201,8 @@ export function getPullRequest(
  * Endpoint documentation: https://docs.github.com/en/rest/pulls/reviews#list-reviews-for-a-pull-request
  */
 export function getPullRequestReviews(
-  url: string,
-  token: string,
+  url: Link,
+  token: Token,
 ): AxiosPromise<PullRequestReview[]> {
   return apiRequestAuth(url, 'GET', token);
 }
@@ -204,14 +212,14 @@ export function getPullRequestReviews(
  *
  * Endpoint documentation: https://docs.github.com/en/rest/releases/releases#get-a-release
  */
-export function getRelease(url: string, token: string): AxiosPromise<Release> {
+export function getRelease(url: Link, token: Token): AxiosPromise<Release> {
   return apiRequestAuth(url, 'GET', token);
 }
 
 /**
  * Get the `html_url` from the GitHub response
  */
-export async function getHtmlUrl(url: string, token: string): Promise<string> {
+export async function getHtmlUrl(url: Link, token: Token): Promise<string> {
   try {
     const response = (await apiRequestAuth(url, 'GET', token)).data;
     return response.html_url;
@@ -230,18 +238,23 @@ export async function searchDiscussions(
   notification: Notification,
 ): AxiosPromise<GraphQLSearch<Discussion>> {
   const url = getGitHubGraphQLUrl(notification.account.hostname);
-  return apiRequestAuth(url.toString(), 'POST', notification.account.token, {
-    query: print(QUERY_SEARCH_DISCUSSIONS),
-    variables: {
-      queryStatement: formatAsGitHubSearchSyntax(
-        notification.repository.full_name,
-        notification.subject.title,
-      ),
-      firstDiscussions: 1,
-      lastComments: 1,
-      lastReplies: 1,
+  return apiRequestAuth(
+    url.toString() as Link,
+    'POST',
+    notification.account.token,
+    {
+      query: print(QUERY_SEARCH_DISCUSSIONS),
+      variables: {
+        queryStatement: formatAsGitHubSearchSyntax(
+          notification.repository.full_name,
+          notification.subject.title,
+        ),
+        firstDiscussions: 1,
+        lastComments: 1,
+        lastReplies: 1,
+      },
     },
-  });
+  );
 }
 
 /**
diff --git a/src/utils/api/request.ts b/src/utils/api/request.ts
index 17132d31..03a71b17 100644
--- a/src/utils/api/request.ts
+++ b/src/utils/api/request.ts
@@ -1,7 +1,8 @@
 import axios, { type AxiosPromise, type Method } from 'axios';
+import type { Link, Token } from '../../types';
 
 export function apiRequest(
-  url: string,
+  url: Link,
   method: Method,
   data = {},
 ): AxiosPromise | null {
@@ -12,9 +13,9 @@ export function apiRequest(
 }
 
 export function apiRequestAuth(
-  url: string,
+  url: Link,
   method: Method,
-  token: string,
+  token: Token,
   data = {},
 ): AxiosPromise | null {
   axios.defaults.headers.common.Accept = 'application/json';
diff --git a/src/utils/api/utils.ts b/src/utils/api/utils.ts
index f217ef6d..52fdf25f 100644
--- a/src/utils/api/utils.ts
+++ b/src/utils/api/utils.ts
@@ -1,7 +1,8 @@
+import type { Hostname } from '../../types';
 import Constants from '../constants';
 import { isEnterpriseHost } from '../helpers';
 
-export function getGitHubAPIBaseUrl(hostname: string): URL {
+export function getGitHubAPIBaseUrl(hostname: Hostname): URL {
   const url = new URL(Constants.GITHUB_API_BASE_URL);
 
   if (isEnterpriseHost(hostname)) {
@@ -11,7 +12,7 @@ export function getGitHubAPIBaseUrl(hostname: string): URL {
   return url;
 }
 
-export function getGitHubGraphQLUrl(hostname: string): URL {
+export function getGitHubGraphQLUrl(hostname: Hostname): URL {
   const url = new URL(Constants.GITHUB_API_GRAPHQL_URL);
 
   if (isEnterpriseHost(hostname)) {
diff --git a/src/utils/auth/types.ts b/src/utils/auth/types.ts
index f51261d8..d66bbbce 100644
--- a/src/utils/auth/types.ts
+++ b/src/utils/auth/types.ts
@@ -1,32 +1,40 @@
+import type {
+  AuthCode,
+  ClientID,
+  ClientSecret,
+  Hostname,
+  Token,
+} from '../../types';
+
 export type AuthMethod = 'GitHub App' | 'Personal Access Token' | 'OAuth App';
 
 export type PlatformType = 'GitHub Cloud' | 'GitHub Enterprise Server';
 
 export interface LoginOAuthAppOptions {
-  hostname: string;
-  clientId: string;
-  clientSecret: string;
+  hostname: Hostname;
+  clientId: ClientID;
+  clientSecret: ClientSecret;
 }
 
 export interface LoginPersonalAccessTokenOptions {
-  hostname: string;
-  token: string;
+  hostname: Hostname;
+  token: Token;
 }
 
 export interface AuthResponse {
-  authCode: string;
+  authCode: AuthCode;
   authOptions: LoginOAuthAppOptions;
 }
 
 export interface AuthTokenResponse {
-  hostname: string;
-  token: string;
+  hostname: Hostname;
+  token: Token;
 }
 
 /**
  * @deprecated This type is deprecated and will be removed in a future release.
  */
 export interface EnterpriseAccount {
-  hostname: string;
-  token: string;
+  hostname: Hostname;
+  token: Token;
 }
diff --git a/src/utils/auth/utils.ts b/src/utils/auth/utils.ts
index a6c3f212..fb62660d 100644
--- a/src/utils/auth/utils.ts
+++ b/src/utils/auth/utils.ts
@@ -1,6 +1,15 @@
 import { BrowserWindow } from '@electron/remote';
 import { format } from 'date-fns';
-import type { Account, AuthState, GitifyUser } from '../../types';
+import type {
+  Account,
+  AuthCode,
+  AuthState,
+  ClientID,
+  GitifyUser,
+  Hostname,
+  Link,
+  Token,
+} from '../../types';
 import type { UserDetails } from '../../typesGitHub';
 import { getAuthenticatedUser } from '../api/client';
 import { apiRequest } from '../api/request';
@@ -27,9 +36,10 @@ export const authGitHub = (
 
     authWindow.loadURL(authUrl);
 
-    const handleCallback = (url: string) => {
+    const handleCallback = (url: Link) => {
       const raw_code = /code=([^&]*)/.exec(url) || null;
-      const authCode = raw_code && raw_code.length > 1 ? raw_code[1] : null;
+      const authCode =
+        raw_code && raw_code.length > 1 ? (raw_code[1] as AuthCode) : null;
       const error = /\?error=(.+)$/.exec(url);
       if (authCode || error) {
         // Close the browser if code found or error
@@ -65,19 +75,19 @@ export const authGitHub = (
 
     authWindow.webContents.on('will-redirect', (event, url) => {
       event.preventDefault();
-      handleCallback(url);
+      handleCallback(url as Link);
     });
 
     authWindow.webContents.on('will-navigate', (event, url) => {
       event.preventDefault();
-      handleCallback(url);
+      handleCallback(url as Link);
     });
   });
 };
 
 export const getUserData = async (
-  token: string,
-  hostname: string,
+  token: Token,
+  hostname: Hostname,
 ): Promise<GitifyUser> => {
   const response: UserDetails = (await getAuthenticatedUser(hostname, token))
     .data;
@@ -90,10 +100,11 @@ export const getUserData = async (
 };
 
 export const getToken = async (
-  authCode: string,
+  authCode: AuthCode,
   authOptions = Constants.DEFAULT_AUTH_OPTIONS,
 ): Promise<AuthTokenResponse> => {
-  const url = `https://${authOptions.hostname}/login/oauth/access_token`;
+  const url =
+    `https://${authOptions.hostname}/login/oauth/access_token` as Link;
   const data = {
     client_id: authOptions.clientId,
     client_secret: authOptions.clientSecret,
@@ -110,8 +121,8 @@ export const getToken = async (
 export function addAccount(
   auth: AuthState,
   method: AuthMethod,
-  token: string,
-  hostname: string,
+  token: Token,
+  hostname: Hostname,
   user?: GitifyUser,
 ): AuthState {
   return {
@@ -138,7 +149,7 @@ export function removeAccount(auth: AuthState, account: Account): AuthState {
   };
 }
 
-export function getDeveloperSettingsURL(account: Account): string {
+export function getDeveloperSettingsURL(account: Account): Link {
   const settingsURL = new URL(`https://${account.hostname}`);
 
   switch (account.method) {
@@ -152,19 +163,19 @@ export function getDeveloperSettingsURL(account: Account): string {
       settingsURL.pathname = '/settings/tokens';
       break;
   }
-  return settingsURL.toString();
+  return settingsURL.toString() as Link;
 }
 
-export function getNewTokenURL(hostname: string): string {
+export function getNewTokenURL(hostname: Hostname): Link {
   const date = format(new Date(), 'PP p');
   const newTokenURL = new URL(`https://${hostname}/settings/tokens/new`);
   newTokenURL.searchParams.append('description', `Gitify (Created on ${date})`);
   newTokenURL.searchParams.append('scopes', Constants.AUTH_SCOPE.join(','));
 
-  return newTokenURL.toString();
+  return newTokenURL.toString() as Link;
 }
 
-export function getNewOAuthAppURL(hostname: string): string {
+export function getNewOAuthAppURL(hostname: Hostname): Link {
   const date = format(new Date(), 'PP p');
   const newOAuthAppURL = new URL(
     `https://${hostname}/settings/applications/new`,
@@ -182,20 +193,20 @@ export function getNewOAuthAppURL(hostname: string): string {
     'https://www.gitify.io/callback',
   );
 
-  return newOAuthAppURL.toString();
+  return newOAuthAppURL.toString() as Link;
 }
 
-export function isValidHostname(hostname: string) {
+export function isValidHostname(hostname: Hostname) {
   return /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/i.test(
     hostname,
   );
 }
 
-export function isValidClientId(clientId: string) {
+export function isValidClientId(clientId: ClientID) {
   return /^[A-Z0-9_]{20}$/i.test(clientId);
 }
 
-export function isValidToken(token: string) {
+export function isValidToken(token: Token) {
   return /^[A-Z0-9_]{40}$/i.test(token);
 }
 
diff --git a/src/utils/comms.ts b/src/utils/comms.ts
index 0e67746a..815992ed 100644
--- a/src/utils/comms.ts
+++ b/src/utils/comms.ts
@@ -1,6 +1,7 @@
 import { ipcRenderer, shell } from 'electron';
+import type { Link } from '../types';
 
-export function openExternalLink(url: string): void {
+export function openExternalLink(url: Link): void {
   if (!url.toLowerCase().startsWith('file:///')) {
     shell.openExternal(url);
   }
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
index 46d17f8f..229c3708 100644
--- a/src/utils/constants.ts
+++ b/src/utils/constants.ts
@@ -1,13 +1,14 @@
-import type { ErrorType, GitifyError } from '../types';
+import type { ErrorType, GitifyError, Link } from '../types';
+import type { ClientID, ClientSecret, Hostname } from '../types';
 
 export const Constants = {
   // GitHub OAuth
   AUTH_SCOPE: ['read:user', 'notifications', 'repo'],
 
   DEFAULT_AUTH_OPTIONS: {
-    hostname: 'github.com',
-    clientId: process.env.OAUTH_CLIENT_ID,
-    clientSecret: process.env.OAUTH_CLIENT_SECRET,
+    hostname: 'github.com' as Hostname,
+    clientId: process.env.OAUTH_CLIENT_ID as ClientID,
+    clientSecret: process.env.OAUTH_CLIENT_SECRET as ClientSecret,
   },
 
   GITHUB_API_BASE_URL: 'https://api.github.com',
@@ -25,11 +26,11 @@ export const Constants = {
   // GitHub Docs
   GITHUB_DOCS: {
     OAUTH_URL:
-      'https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authenticating-to-the-rest-api-with-an-oauth-app',
+      'https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authenticating-to-the-rest-api-with-an-oauth-app' as Link,
     PAT_URL:
-      'https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens',
+      'https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens' as Link,
     PARTICIPATING_URL:
-      'https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#about-participating-and-watching-notifications',
+      'https://docs.github.com/en/account-and-profile/managing-subscriptions-and-notifications-on-github/setting-up-notifications/configuring-notifications#about-participating-and-watching-notifications' as Link,
   },
 };
 
diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts
index 2032e84e..86ee2f5d 100644
--- a/src/utils/helpers.ts
+++ b/src/utils/helpers.ts
@@ -1,4 +1,5 @@
 import { formatDistanceToNowStrict, parseISO } from 'date-fns';
+import type { Hostname, Link } from '../types';
 import type { Notification } from '../typesGitHub';
 import { getHtmlUrl, getLatestDiscussion } from './api/client';
 import type { PlatformType } from './auth/types';
@@ -15,7 +16,7 @@ export function getPlatformFromHostname(hostname: string): PlatformType {
     : 'GitHub Enterprise Server';
 }
 
-export function isEnterpriseHost(hostname: string): boolean {
+export function isEnterpriseHost(hostname: Hostname): boolean {
   return !hostname.endsWith(Constants.DEFAULT_AUTH_OPTIONS.hostname);
 }
 
@@ -28,7 +29,7 @@ export function generateNotificationReferrerId(
   return buffer.toString('base64');
 }
 
-export function getCheckSuiteUrl(notification: Notification): string {
+export function getCheckSuiteUrl(notification: Notification): Link {
   const filters = [];
 
   const checkSuiteAttributes = getCheckSuiteAttributes(notification);
@@ -50,7 +51,7 @@ export function getCheckSuiteUrl(notification: Notification): string {
   return actionsURL(notification.repository.html_url, filters);
 }
 
-export function getWorkflowRunUrl(notification: Notification): string {
+export function getWorkflowRunUrl(notification: Notification): Link {
   const filters = [];
 
   const workflowRunAttributes = getWorkflowRunAttributes(notification);
@@ -65,7 +66,7 @@ export function getWorkflowRunUrl(notification: Notification): string {
 /**
  * Construct a GitHub Actions URL for a repository with optional filters.
  */
-export function actionsURL(repositoryURL: string, filters: string[]): string {
+export function actionsURL(repositoryURL: string, filters: string[]): Link {
   const url = new URL(repositoryURL);
   url.pathname += '/actions';
 
@@ -74,10 +75,10 @@ export function actionsURL(repositoryURL: string, filters: string[]): string {
   }
 
   // Note: the GitHub Actions UI cannot handle encoded '+' characters.
-  return url.toString().replace(/%2B/g, '+');
+  return url.toString().replace(/%2B/g, '+') as Link;
 }
 
-async function getDiscussionUrl(notification: Notification): Promise<string> {
+async function getDiscussionUrl(notification: Notification): Promise<Link> {
   const url = new URL(notification.repository.html_url);
   url.pathname += '/discussions';
 
@@ -93,12 +94,12 @@ async function getDiscussionUrl(notification: Notification): Promise<string> {
     }
   }
 
-  return url.toString();
+  return url.toString() as Link;
 }
 
 export async function generateGitHubWebUrl(
   notification: Notification,
-): Promise<string> {
+): Promise<Link> {
   const url = new URL(notification.repository.html_url);
 
   if (notification.subject.latest_comment_url) {
@@ -136,7 +137,7 @@ export async function generateGitHubWebUrl(
     generateNotificationReferrerId(notification),
   );
 
-  return url.toString();
+  return url.toString() as Link;
 }
 
 export function formatForDisplay(text: string[]): string {
diff --git a/src/utils/links.ts b/src/utils/links.ts
index 69cf8f8f..a307da4a 100644
--- a/src/utils/links.ts
+++ b/src/utils/links.ts
@@ -1,4 +1,4 @@
-import type { Account } from '../types';
+import type { Account, Hostname, Link } from '../types';
 import type { Notification, Repository, SubjectUser } from '../typesGitHub';
 import { getDeveloperSettingsURL } from './auth/utils';
 import { openExternalLink } from './comms';
@@ -6,31 +6,31 @@ import Constants from './constants';
 import { generateGitHubWebUrl } from './helpers';
 
 export function openGitifyRepository() {
-  openExternalLink(`https://github.com/${Constants.REPO_SLUG}`);
+  openExternalLink(`https://github.com/${Constants.REPO_SLUG}` as Link);
 }
 
 export function openGitifyReleaseNotes(version: string) {
   openExternalLink(
-    `https://github.com/${Constants.REPO_SLUG}/releases/tag/v${version}`,
+    `https://github.com/${Constants.REPO_SLUG}/releases/tag/v${version}` as Link,
   );
 }
 
 export function openGitHubNotifications() {
-  openExternalLink('https://github.com/notifications');
+  openExternalLink('https://github.com/notifications' as Link);
 }
 
 export function openAccountProfile(account: Account) {
   const url = new URL(`https://${account.hostname}`);
   url.pathname = account.user.login;
-  openExternalLink(url.toString());
+  openExternalLink(url.toString() as Link);
 }
 
 export function openUserProfile(user: SubjectUser) {
   openExternalLink(user.html_url);
 }
 
-export function openHost(hostname: string) {
-  openExternalLink(`https://${hostname}`);
+export function openHost(hostname: Hostname) {
+  openExternalLink(`https://${hostname}` as Link);
 }
 
 export function openDeveloperSettings(account: Account) {
diff --git a/src/utils/subject.ts b/src/utils/subject.ts
index ce85134b..ba0c7853 100644
--- a/src/utils/subject.ts
+++ b/src/utils/subject.ts
@@ -1,3 +1,4 @@
+import type { Link } from '../types';
 import type {
   CheckSuiteAttributes,
   CheckSuiteStatus,
@@ -294,7 +295,7 @@ export async function getLatestReviewForReviewers(
   }
 
   const prReviews = await getPullRequestReviews(
-    `${notification.subject.url}/reviews`,
+    `${notification.subject.url}/reviews` as Link,
     notification.account.token,
   );
 


Test patch:
diff --git a/src/components/NotificationRow.test.tsx b/src/components/NotificationRow.test.tsx
index 99f249a5..0473aa2c 100644
--- a/src/components/NotificationRow.test.tsx
+++ b/src/components/NotificationRow.test.tsx
@@ -5,6 +5,7 @@ import {
   mockSettings,
 } from '../__mocks__/state-mocks';
 import { AppContext } from '../context/App';
+import type { Link } from '../types';
 import type { Milestone, UserType } from '../typesGitHub';
 import { mockSingleNotification } from '../utils/api/__mocks__/response-mocks';
 import * as comms from '../utils/comms';
@@ -473,9 +474,9 @@ describe('components/NotificationRow.tsx', () => {
             ...mockSingleNotification.subject,
             user: {
               login: 'some-user',
-              html_url: 'https://github.com/some-user',
+              html_url: 'https://github.com/some-user' as Link,
               avatar_url:
-                'https://avatars.githubusercontent.com/u/123456789?v=4',
+                'https://avatars.githubusercontent.com/u/123456789?v=4' as Link,
               type: 'User' as UserType,
             },
             reviews: null,
diff --git a/src/components/Repository.test.tsx b/src/components/Repository.test.tsx
index 5cf5dde2..cf2fa776 100644
--- a/src/components/Repository.test.tsx
+++ b/src/components/Repository.test.tsx
@@ -1,6 +1,7 @@
 import { fireEvent, render, screen } from '@testing-library/react';
 import { mockGitHubCloudAccount } from '../__mocks__/state-mocks';
 import { AppContext } from '../context/App';
+import type { Link } from '../types';
 import {
   mockGitHubNotifications,
   mockSingleNotification,
@@ -81,7 +82,7 @@ describe('components/Repository.tsx', () => {
   });
 
   it('should use default repository icon when avatar is not available', () => {
-    props.repoNotifications[0].repository.owner.avatar_url = '';
+    props.repoNotifications[0].repository.owner.avatar_url = '' as Link;
 
     const tree = render(
       <AppContext.Provider value={{}}>
diff --git a/src/components/fields/Button.test.tsx b/src/components/fields/Button.test.tsx
index e0472eb4..677f2409 100644
--- a/src/components/fields/Button.test.tsx
+++ b/src/components/fields/Button.test.tsx
@@ -1,6 +1,7 @@
 import { MarkGithubIcon } from '@primer/octicons-react';
 import { fireEvent, render, screen } from '@testing-library/react';
 import { shell } from 'electron';
+import type { Link } from '../../types';
 import { Button, type IButton } from './Button';
 
 describe('components/fields/Button.tsx', () => {
@@ -27,7 +28,7 @@ describe('components/fields/Button.tsx', () => {
   });
 
   it('should render with url', () => {
-    render(<Button {...props} url="https://github.com" />);
+    render(<Button {...props} url={'https://github.com' as Link} />);
 
     const buttonElement = screen.getByLabelText('button');
 
diff --git a/src/context/App.test.tsx b/src/context/App.test.tsx
index becbd189..f7cc6191 100644
--- a/src/context/App.test.tsx
+++ b/src/context/App.test.tsx
@@ -2,7 +2,7 @@ import { act, fireEvent, render, waitFor } from '@testing-library/react';
 import { useContext } from 'react';
 import { mockAuth, mockSettings } from '../__mocks__/state-mocks';
 import { useNotifications } from '../hooks/useNotifications';
-import type { AuthState, SettingsState } from '../types';
+import type { AuthState, Hostname, SettingsState, Token } from '../types';
 import { mockSingleNotification } from '../utils/api/__mocks__/response-mocks';
 import * as apiRequests from '../utils/api/request';
 import * as comms from '../utils/comms';
@@ -280,8 +280,8 @@ describe('context/App.tsx', () => {
             type="button"
             onClick={() =>
               loginWithPersonalAccessToken({
-                hostname: 'github.com',
-                token: '123-456',
+                hostname: 'github.com' as Hostname,
+                token: '123-456' as Token,
               })
             }
           >
diff --git a/src/routes/LoginWithOAuthApp.test.tsx b/src/routes/LoginWithOAuthApp.test.tsx
index cd062d6a..01156267 100644
--- a/src/routes/LoginWithOAuthApp.test.tsx
+++ b/src/routes/LoginWithOAuthApp.test.tsx
@@ -2,7 +2,7 @@ import { fireEvent, render, screen } from '@testing-library/react';
 import { shell } from 'electron';
 import { MemoryRouter } from 'react-router-dom';
 import { AppContext } from '../context/App';
-import type { AuthState } from '../types';
+import type { AuthState, ClientID, ClientSecret, Hostname } from '../types';
 import { LoginWithOAuthApp, validate } from './LoginWithOAuthApp';
 
 const mockNavigate = jest.fn();
@@ -64,9 +64,9 @@ describe('routes/LoginWithOAuthApp.tsx', () => {
 
     values = {
       ...emptyValues,
-      hostname: 'hello',
-      clientId: '!@£INVALID-.1',
-      clientSecret: '!@£INVALID-.1',
+      hostname: 'hello' as Hostname,
+      clientId: '!@£INVALID-.1' as ClientID,
+      clientSecret: '!@£INVALID-.1' as ClientSecret,
     };
     expect(validate(values).hostname).toBe('Invalid hostname.');
     expect(validate(values).clientId).toBe('Invalid client id.');
diff --git a/src/utils/api/client.test.ts b/src/utils/api/client.test.ts
index 526866f8..7065150a 100644
--- a/src/utils/api/client.test.ts
+++ b/src/utils/api/client.test.ts
@@ -4,7 +4,7 @@ import {
   mockGitHubEnterpriseServerAccount,
   mockToken,
 } from '../../__mocks__/state-mocks';
-import type { SettingsState } from '../../types';
+import type { Hostname, Link, SettingsState, Token } from '../../types';
 import {
   getAuthenticatedUser,
   getHtmlUrl,
@@ -19,8 +19,8 @@ import * as apiRequests from './request';
 
 jest.mock('axios');
 
-const mockGitHubHostname = 'github.com';
-const mockEnterpriseHostname = 'example.com';
+const mockGitHubHostname = 'github.com' as Hostname;
+const mockEnterpriseHostname = 'example.com' as Hostname;
 const mockThreadId = '1234';
 const mockRepoSlug = 'gitify-app/notifications-test';
 
@@ -269,8 +269,8 @@ describe('utils/api/client.ts', () => {
       apiRequestAuthMock.mockResolvedValue(requestPromise);
 
       const result = await getHtmlUrl(
-        'https://api.github.com/repos/gitify-app/notifications-test/issues/785',
-        '123',
+        'https://api.github.com/repos/gitify-app/notifications-test/issues/785' as Link,
+        '123' as Token,
       );
       expect(result).toBe(
         'https://github.com/gitify-app/notifications-test/issues/785',
@@ -287,8 +287,8 @@ describe('utils/api/client.ts', () => {
       apiRequestAuthMock.mockRejectedValue(mockError);
 
       await getHtmlUrl(
-        'https://api.github.com/repos/gitify-app/gitify/issues/785',
-        '123',
+        'https://api.github.com/repos/gitify-app/gitify/issues/785' as Link,
+        '123' as Token,
       );
 
       expect(consoleErrorSpy).toHaveBeenCalledWith('Failed to get html url');
diff --git a/src/utils/api/errors.test.ts b/src/utils/api/errors.test.ts
index 240eea26..792d31b1 100644
--- a/src/utils/api/errors.test.ts
+++ b/src/utils/api/errors.test.ts
@@ -1,4 +1,5 @@
 import { AxiosError, type AxiosResponse } from 'axios';
+import type { Link } from '../../types';
 import type { GitHubRESTError } from '../../typesGitHub';
 import { Errors } from '../constants';
 import { determineFailureType } from './errors';
@@ -111,7 +112,7 @@ function createMockResponse(
   return {
     data: {
       message,
-      documentation_url: 'https://some-url.com',
+      documentation_url: 'https://some-url.com' as Link,
     },
     status,
     statusText: 'Some status text',
diff --git a/src/utils/api/request.test.ts b/src/utils/api/request.test.ts
index 45b5ee7a..6be72fb5 100644
--- a/src/utils/api/request.test.ts
+++ b/src/utils/api/request.test.ts
@@ -1,9 +1,10 @@
 import axios from 'axios';
+import type { Link, Token } from '../../types';
 import { apiRequest, apiRequestAuth } from './request';
 
 jest.mock('axios');
 
-const url = 'https://example.com';
+const url = 'https://example.com' as Link;
 const method = 'get';
 
 describe('utils/api/request.ts', () => {
@@ -40,7 +41,7 @@ describe('utils/api/request.ts', () => {
 });
 
 describe('apiRequestAuth', () => {
-  const token = 'yourAuthToken';
+  const token = 'yourAuthToken' as Token;
 
   afterEach(() => {
     jest.resetAllMocks();
diff --git a/src/utils/api/utils.test.ts b/src/utils/api/utils.test.ts
index 8c05e4ac..e6d488af 100644
--- a/src/utils/api/utils.test.ts
+++ b/src/utils/api/utils.test.ts
@@ -1,26 +1,27 @@
+import type { Hostname } from '../../types';
 import { getGitHubAPIBaseUrl, getGitHubGraphQLUrl } from './utils';
 
 describe('utils/api/utils.ts', () => {
   describe('getGitHubAPIBaseUrl', () => {
     it('should generate a GitHub API url - non enterprise', () => {
-      const result = getGitHubAPIBaseUrl('github.com');
+      const result = getGitHubAPIBaseUrl('github.com' as Hostname);
       expect(result.toString()).toBe('https://api.github.com/');
     });
 
     it('should generate a GitHub API url - enterprise', () => {
-      const result = getGitHubAPIBaseUrl('github.gitify.io');
+      const result = getGitHubAPIBaseUrl('github.gitify.io' as Hostname);
       expect(result.toString()).toBe('https://github.gitify.io/api/v3/');
     });
   });
 
   describe('getGitHubGraphQLUrl', () => {
     it('should generate a GitHub GraphQL url - non enterprise', () => {
-      const result = getGitHubGraphQLUrl('github.com');
+      const result = getGitHubGraphQLUrl('github.com' as Hostname);
       expect(result.toString()).toBe('https://api.github.com/graphql');
     });
 
     it('should generate a GitHub GraphQL url - enterprise', () => {
-      const result = getGitHubGraphQLUrl('github.gitify.io');
+      const result = getGitHubGraphQLUrl('github.gitify.io' as Hostname);
       expect(result.toString()).toBe('https://github.gitify.io/api/graphql');
     });
   });
diff --git a/src/utils/auth/migration.test.ts b/src/utils/auth/migration.test.ts
index 12832ab4..82c25669 100644
--- a/src/utils/auth/migration.test.ts
+++ b/src/utils/auth/migration.test.ts
@@ -1,7 +1,7 @@
 import axios from 'axios';
 import nock from 'nock';
 import { mockGitifyUser, mockToken } from '../../__mocks__/state-mocks';
-import type { AuthState } from '../../types';
+import type { AuthState, Hostname } from '../../types';
 import Constants from '../constants';
 import {
   convertAccounts,
@@ -61,7 +61,7 @@ describe('utils/auth/migration.ts', () => {
       expect(
         hasAccountsToMigrate({
           enterpriseAccounts: [
-            { hostname: 'github.gitify.io', token: mockToken },
+            { hostname: 'github.gitify.io' as Hostname, token: mockToken },
           ],
         } as AuthState),
       ).toBe(true);
@@ -72,9 +72,9 @@ describe('utils/auth/migration.ts', () => {
         hasAccountsToMigrate({
           token: mockToken,
           enterpriseAccounts: [
-            { hostname: 'github.gitify.io', token: mockToken },
+            { hostname: 'github.gitify.io' as Hostname, token: mockToken },
           ],
-          accounts: [{ hostname: 'github.com', token: mockToken }],
+          accounts: [{ hostname: 'github.com' as Hostname, token: mockToken }],
         } as AuthState),
       ).toBe(false);
     });
@@ -107,13 +107,13 @@ describe('utils/auth/migration.ts', () => {
 
       const result = await convertAccounts({
         enterpriseAccounts: [
-          { hostname: 'github.gitify.io', token: mockToken },
+          { hostname: 'github.gitify.io' as Hostname, token: mockToken },
         ],
       } as AuthState);
 
       expect(result).toEqual([
         {
-          hostname: 'github.gitify.io',
+          hostname: 'github.gitify.io' as Hostname,
           platform: 'GitHub Enterprise Server',
           method: 'OAuth App',
           token: mockToken,
@@ -132,7 +132,7 @@ describe('utils/auth/migration.ts', () => {
         token: mockToken,
         user: mockGitifyUser,
         enterpriseAccounts: [
-          { hostname: 'github.gitify.io', token: mockToken },
+          { hostname: 'github.gitify.io' as Hostname, token: mockToken },
         ],
       } as AuthState);
 
@@ -145,7 +145,7 @@ describe('utils/auth/migration.ts', () => {
           user: mockGitifyUser,
         },
         {
-          hostname: 'github.gitify.io',
+          hostname: 'github.gitify.io' as Hostname,
           platform: 'GitHub Enterprise Server',
           method: 'OAuth App',
           token: mockToken,
diff --git a/src/utils/auth/utils.test.ts b/src/utils/auth/utils.test.ts
index f120fd49..0aa07853 100644
--- a/src/utils/auth/utils.test.ts
+++ b/src/utils/auth/utils.test.ts
@@ -1,7 +1,14 @@
 import remote from '@electron/remote';
 import type { AxiosPromise, AxiosResponse } from 'axios';
 import { mockAuth, mockGitHubCloudAccount } from '../../__mocks__/state-mocks';
-import type { Account, AuthState } from '../../types';
+import type {
+  Account,
+  AuthCode,
+  AuthState,
+  ClientID,
+  Hostname,
+  Token,
+} from '../../types';
 import * as apiRequests from '../api/request';
 import * as auth from './utils';
 import { getNewOAuthAppURL, getNewTokenURL } from './utils';
@@ -63,7 +70,7 @@ describe('utils/auth/utils.ts', () => {
   });
 
   describe('getToken', () => {
-    const authCode = '123-456';
+    const authCode = '123-456' as AuthCode;
     const apiRequestMock = jest.spyOn(apiRequests, 'apiRequest');
 
     it('should get a token - success', async () => {
@@ -85,7 +92,7 @@ describe('utils/auth/utils.ts', () => {
         },
       );
       expect(res.token).toBe('this-is-a-token');
-      expect(res.hostname).toBe('github.com');
+      expect(res.hostname).toBe('github.com' as Hostname);
     });
 
     it('should get a token - failure', async () => {
@@ -117,16 +124,16 @@ describe('utils/auth/utils.ts', () => {
         const result = auth.addAccount(
           mockAuthState,
           'Personal Access Token',
-          '123-456',
-          'github.com',
+          '123-456' as Token,
+          'github.com' as Hostname,
         );
 
         expect(result.accounts).toEqual([
           {
-            hostname: 'github.com',
+            hostname: 'github.com' as Hostname,
             method: 'Personal Access Token',
             platform: 'GitHub Cloud',
-            token: '123-456',
+            token: '123-456' as Token,
             user: undefined,
           },
         ]);
@@ -136,16 +143,16 @@ describe('utils/auth/utils.ts', () => {
         const result = auth.addAccount(
           mockAuthState,
           'OAuth App',
-          '123-456',
-          'github.com',
+          '123-456' as Token,
+          'github.com' as Hostname,
         );
 
         expect(result.accounts).toEqual([
           {
-            hostname: 'github.com',
+            hostname: 'github.com' as Hostname,
             method: 'OAuth App',
             platform: 'GitHub Cloud',
-            token: '123-456',
+            token: '123-456' as Token,
             user: undefined,
           },
         ]);
@@ -157,16 +164,16 @@ describe('utils/auth/utils.ts', () => {
         const result = auth.addAccount(
           mockAuthState,
           'Personal Access Token',
-          '123-456',
-          'github.gitify.io',
+          '123-456' as Token,
+          'github.gitify.io' as Hostname,
         );
 
         expect(result.accounts).toEqual([
           {
-            hostname: 'github.gitify.io',
+            hostname: 'github.gitify.io' as Hostname,
             method: 'Personal Access Token',
             platform: 'GitHub Enterprise Server',
-            token: '123-456',
+            token: '123-456' as Token,
             user: undefined,
           },
         ]);
@@ -176,16 +183,16 @@ describe('utils/auth/utils.ts', () => {
         const result = auth.addAccount(
           mockAuthState,
           'OAuth App',
-          '123-456',
-          'github.gitify.io',
+          '123-456' as Token,
+          'github.gitify.io' as Hostname,
         );
 
         expect(result.accounts).toEqual([
           {
-            hostname: 'github.gitify.io',
+            hostname: 'github.gitify.io' as Hostname,
             method: 'OAuth App',
             platform: 'GitHub Enterprise Server',
-            token: '123-456',
+            token: '123-456' as Token,
             user: undefined,
           },
         ]);
@@ -218,19 +225,19 @@ describe('utils/auth/utils.ts', () => {
   it('getDeveloperSettingsURL', () => {
     expect(
       auth.getDeveloperSettingsURL({
-        hostname: 'github.com',
+        hostname: 'github.com' as Hostname,
         method: 'GitHub App',
       } as Account),
     ).toBe('https://github.com/settings/apps');
     expect(
       auth.getDeveloperSettingsURL({
-        hostname: 'github.com',
+        hostname: 'github.com' as Hostname,
         method: 'OAuth App',
       } as Account),
     ).toBe('https://github.com/settings/developers');
     expect(
       auth.getDeveloperSettingsURL({
-        hostname: 'github.com',
+        hostname: 'github.com' as Hostname,
         method: 'Personal Access Token',
       } as Account),
     ).toBe('https://github.com/settings/tokens');
@@ -239,7 +246,7 @@ describe('utils/auth/utils.ts', () => {
   describe('getNewTokenURL', () => {
     it('should generate new PAT url - github cloud', () => {
       expect(
-        getNewTokenURL('github.com').startsWith(
+        getNewTokenURL('github.com' as Hostname).startsWith(
           'https://github.com/settings/tokens/new',
         ),
       ).toBeTruthy();
@@ -247,7 +254,7 @@ describe('utils/auth/utils.ts', () => {
 
     it('should generate new PAT url - github server', () => {
       expect(
-        getNewTokenURL('github.gitify.io').startsWith(
+        getNewTokenURL('github.gitify.io' as Hostname).startsWith(
           'https://github.gitify.io/settings/tokens/new',
         ),
       ).toBeTruthy();
@@ -257,7 +264,7 @@ describe('utils/auth/utils.ts', () => {
   describe('getNewOAuthAppURL', () => {
     it('should generate new oauth app url - github cloud', () => {
       expect(
-        getNewOAuthAppURL('github.com').startsWith(
+        getNewOAuthAppURL('github.com' as Hostname).startsWith(
           'https://github.com/settings/applications/new',
         ),
       ).toBeTruthy();
@@ -265,7 +272,7 @@ describe('utils/auth/utils.ts', () => {
 
     it('should generate new oauth app url - github server', () => {
       expect(
-        getNewOAuthAppURL('github.gitify.io').startsWith(
+        getNewOAuthAppURL('github.gitify.io' as Hostname).startsWith(
           'https://github.gitify.io/settings/applications/new',
         ),
       ).toBeTruthy();
@@ -274,49 +281,51 @@ describe('utils/auth/utils.ts', () => {
 
   describe('isValidHostname', () => {
     it('should validate hostname - github cloud', () => {
-      expect(auth.isValidHostname('github.com')).toBeTruthy();
+      expect(auth.isValidHostname('github.com' as Hostname)).toBeTruthy();
     });
 
     it('should validate hostname - github enterprise server', () => {
-      expect(auth.isValidHostname('github.gitify.io')).toBeTruthy();
+      expect(auth.isValidHostname('github.gitify.io' as Hostname)).toBeTruthy();
     });
 
     it('should invalidate hostname - empty', () => {
-      expect(auth.isValidHostname('')).toBeFalsy();
+      expect(auth.isValidHostname('' as Hostname)).toBeFalsy();
     });
 
     it('should invalidate hostname - invalid', () => {
-      expect(auth.isValidHostname('github')).toBeFalsy();
+      expect(auth.isValidHostname('github' as Hostname)).toBeFalsy();
     });
   });
 
   describe('isValidClientId', () => {
     it('should validate client id - valid', () => {
-      expect(auth.isValidClientId('1234567890_ASDFGHJKL')).toBeTruthy();
+      expect(
+        auth.isValidClientId('1234567890_ASDFGHJKL' as ClientID),
+      ).toBeTruthy();
     });
 
     it('should validate client id - empty', () => {
-      expect(auth.isValidClientId('')).toBeFalsy();
+      expect(auth.isValidClientId('' as ClientID)).toBeFalsy();
     });
 
     it('should validate client id - invalid', () => {
-      expect(auth.isValidClientId('1234567890asdfg')).toBeFalsy();
+      expect(auth.isValidClientId('1234567890asdfg' as ClientID)).toBeFalsy();
     });
   });
 
   describe('isValidToken', () => {
     it('should validate token - valid', () => {
       expect(
-        auth.isValidToken('1234567890_asdfghjklPOIUYTREWQ0987654321'),
+        auth.isValidToken('1234567890_asdfghjklPOIUYTREWQ0987654321' as Token),
       ).toBeTruthy();
     });
 
     it('should validate token - empty', () => {
-      expect(auth.isValidToken('')).toBeFalsy();
+      expect(auth.isValidToken('' as Token)).toBeFalsy();
     });
 
     it('should validate token - invalid', () => {
-      expect(auth.isValidToken('1234567890asdfg')).toBeFalsy();
+      expect(auth.isValidToken('1234567890asdfg' as Token)).toBeFalsy();
     });
   });
 });
diff --git a/src/utils/comms.test.ts b/src/utils/comms.test.ts
index 2fa6cb88..0bde2bf6 100644
--- a/src/utils/comms.test.ts
+++ b/src/utils/comms.test.ts
@@ -1,4 +1,5 @@
 import { ipcRenderer, shell } from 'electron';
+import type { Link } from '../types';
 import {
   getAppVersion,
   hideWindow,
@@ -58,13 +59,13 @@ describe('utils/comms.ts', () => {
   });
 
   it('should open an external link', () => {
-    openExternalLink('http://www.gitify.io/');
+    openExternalLink('http://www.gitify.io/' as Link);
     expect(shell.openExternal).toHaveBeenCalledTimes(1);
     expect(shell.openExternal).toHaveBeenCalledWith('http://www.gitify.io/');
   });
 
   it('should ignore opening external local links file:///', () => {
-    openExternalLink('file:///Applications/SomeApp.app');
+    openExternalLink('file:///Applications/SomeApp.app' as Link);
     expect(shell.openExternal).toHaveBeenCalledTimes(0);
   });
 
diff --git a/src/utils/helpers.test.ts b/src/utils/helpers.test.ts
index 25b15991..ab4f45a2 100644
--- a/src/utils/helpers.test.ts
+++ b/src/utils/helpers.test.ts
@@ -1,6 +1,7 @@
 import type { AxiosPromise, AxiosResponse } from 'axios';
 import { mockPersonalAccessTokenAccount } from '../__mocks__/state-mocks';
 
+import type { Hostname, Link } from '../types';
 import type { SubjectType } from '../typesGitHub';
 import {
   mockGraphQLResponse,
@@ -19,15 +20,19 @@ import {
 describe('utils/helpers.ts', () => {
   describe('getPlatformFromHostname', () => {
     it('should return GitHub Cloud', () => {
-      expect(getPlatformFromHostname('github.com')).toBe('GitHub Cloud');
-      expect(getPlatformFromHostname('api.github.com')).toBe('GitHub Cloud');
+      expect(getPlatformFromHostname('github.com' as Hostname)).toBe(
+        'GitHub Cloud',
+      );
+      expect(getPlatformFromHostname('api.github.com' as Hostname)).toBe(
+        'GitHub Cloud',
+      );
     });
 
     it('should return GitHub Enterprise Server', () => {
-      expect(getPlatformFromHostname('github.gitify.app')).toBe(
+      expect(getPlatformFromHostname('github.gitify.app' as Hostname)).toBe(
         'GitHub Enterprise Server',
       );
-      expect(getPlatformFromHostname('api.github.gitify.app')).toBe(
+      expect(getPlatformFromHostname('api.github.gitify.app' as Hostname)).toBe(
         'GitHub Enterprise Server',
       );
     });
@@ -35,13 +40,13 @@ describe('utils/helpers.ts', () => {
 
   describe('isEnterpriseHost', () => {
     it('should return true for enterprise host', () => {
-      expect(isEnterpriseHost('github.gitify.app')).toBe(true);
-      expect(isEnterpriseHost('api.github.gitify.app')).toBe(true);
+      expect(isEnterpriseHost('github.gitify.app' as Hostname)).toBe(true);
+      expect(isEnterpriseHost('api.github.gitify.app' as Hostname)).toBe(true);
     });
 
     it('should return false for non-enterprise host', () => {
-      expect(isEnterpriseHost('github.com')).toBe(false);
-      expect(isEnterpriseHost('api.github.com')).toBe(false);
+      expect(isEnterpriseHost('github.com' as Hostname)).toBe(false);
+      expect(isEnterpriseHost('api.github.com' as Hostname)).toBe(false);
     });
   });
 
@@ -68,9 +73,9 @@ describe('utils/helpers.ts', () => {
     it('Subject Latest Comment Url: when not null, fetch latest comment html url', async () => {
       const subject = {
         title: 'generate github web url unit tests',
-        url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1',
+        url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1' as Link,
         latest_comment_url:
-          'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302888448',
+          'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302888448' as Link,
         type: 'Issue' as SubjectType,
       };
 
@@ -101,7 +106,7 @@ describe('utils/helpers.ts', () => {
     it('Subject Url: when no latest comment url available, fetch subject html url', async () => {
       const subject = {
         title: 'generate github web url unit tests',
-        url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1',
+        url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1' as Link,
         latest_comment_url: null,
         type: 'Issue' as SubjectType,
       };
diff --git a/src/utils/links.test.ts b/src/utils/links.test.ts
index 1a5279b8..dae46773 100644
--- a/src/utils/links.test.ts
+++ b/src/utils/links.test.ts
@@ -1,5 +1,6 @@
 import { partialMockUser } from '../__mocks__/partial-mocks';
 import { mockGitHubCloudAccount } from '../__mocks__/state-mocks';
+import type { Hostname, Link } from '../types';
 import type { Repository } from '../typesGitHub';
 import { mockSingleNotification } from './api/__mocks__/response-mocks';
 import * as authUtils from './auth/utils';
@@ -65,12 +66,12 @@ describe('utils/links.ts', () => {
   });
 
   it('openHost', () => {
-    openHost('github.com');
+    openHost('github.com' as Hostname);
     expect(comms.openExternalLink).toHaveBeenCalledWith('https://github.com');
   });
 
   it('openDeveloperSettings', () => {
-    const mockSettingsURL = 'https://github.com/settings/tokens';
+    const mockSettingsURL = 'https://github.com/settings/tokens' as Link;
 
     jest
       .spyOn(authUtils, 'getDeveloperSettingsURL')
diff --git a/src/utils/notifications.test.ts b/src/utils/notifications.test.ts
index 580fbb06..5cf04ff1 100644
--- a/src/utils/notifications.test.ts
+++ b/src/utils/notifications.test.ts
@@ -5,7 +5,7 @@ import {
 import { partialMockNotification } from '../__mocks__/partial-mocks';
 import { mockAuth, mockSettings } from '../__mocks__/state-mocks';
 import { defaultSettings } from '../context/App';
-import type { SettingsState } from '../types';
+import type { Link, SettingsState } from '../types';
 import { mockGitHubNotifications } from './api/__mocks__/response-mocks';
 import * as comms from './comms';
 import * as links from './links';
@@ -150,9 +150,9 @@ describe('utils/notifications.ts', () => {
         title: 'User authored notification',
         user: {
           login: 'user',
-          html_url: 'https://github.com/user',
+          html_url: 'https://github.com/user' as Link,
           avatar_url:
-            'https://avatars.githubusercontent.com/u/133795385?s=200&v=4',
+            'https://avatars.githubusercontent.com/u/133795385?s=200&v=4' as Link,
           type: 'User',
         },
       }),
@@ -160,9 +160,9 @@ describe('utils/notifications.ts', () => {
         title: 'Bot authored notification',
         user: {
           login: 'bot',
-          html_url: 'https://github.com/bot',
+          html_url: 'https://github.com/bot' as Link,
           avatar_url:
-            'https://avatars.githubusercontent.com/u/133795385?s=200&v=4',
+            'https://avatars.githubusercontent.com/u/133795385?s=200&v=4' as Link,
           type: 'Bot',
         },
       }),
diff --git a/src/utils/storage.test.ts b/src/utils/storage.test.ts
index 42ca9a87..41794ce8 100644
--- a/src/utils/storage.test.ts
+++ b/src/utils/storage.test.ts
@@ -1,4 +1,5 @@
 import { mockSettings } from '../__mocks__/state-mocks';
+import type { Token } from '../types';
 import Constants from './constants';
 import { clearState, loadState, saveState } from './storage';
 
@@ -12,7 +13,7 @@ describe('utils/storage.ts', () => {
               hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
               platform: 'GitHub Cloud',
               method: 'Personal Access Token',
-              token: '123-456',
+              token: '123-456' as Token,
               user: null,
             },
           ],
@@ -27,7 +28,7 @@ describe('utils/storage.ts', () => {
         hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
         platform: 'GitHub Cloud',
         method: 'Personal Access Token',
-        token: '123-456',
+        token: '123-456' as Token,
         user: null,
       },
     ]);
@@ -56,7 +57,7 @@ describe('utils/storage.ts', () => {
             hostname: Constants.DEFAULT_AUTH_OPTIONS.hostname,
             platform: 'GitHub Cloud',
             method: 'Personal Access Token',
-            token: '123-456',
+            token: '123-456' as Token,
             user: null,
           },
         ],
diff --git a/src/utils/subject.test.ts b/src/utils/subject.test.ts
index 7c134f45..9bd3a3af 100644
--- a/src/utils/subject.test.ts
+++ b/src/utils/subject.test.ts
@@ -5,6 +5,7 @@ import {
   partialMockNotification,
   partialMockUser,
 } from '../__mocks__/partial-mocks';
+import type { Link } from '../types';
 import type {
   Discussion,
   DiscussionAuthor,
@@ -25,8 +26,8 @@ const mockAuthor = partialMockUser('some-author');
 const mockCommenter = partialMockUser('some-commenter');
 const mockDiscussionAuthor: DiscussionAuthor = {
   login: 'discussion-author',
-  url: 'https://github.com/discussion-author',
-  avatar_url: 'https://avatars.githubusercontent.com/u/123456789?v=4',
+  url: 'https://github.com/discussion-author' as Link,
+  avatar_url: 'https://avatars.githubusercontent.com/u/123456789?v=4' as Link,
   type: 'User',
 };
 
@@ -136,9 +137,9 @@ describe('utils/subject.ts', () => {
         const mockNotification = partialMockNotification({
           title: 'This is a commit with comments',
           type: 'Commit',
-          url: 'https://api.github.com/repos/gitify-app/notifications-test/commits/d2a86d80e3d24ea9510d5de6c147e53c30f313a8',
+          url: 'https://api.github.com/repos/gitify-app/notifications-test/commits/d2a86d80e3d24ea9510d5de6c147e53c30f313a8' as Link,
           latest_comment_url:
-            'https://api.github.com/repos/gitify-app/notifications-test/comments/141012658',
+            'https://api.github.com/repos/gitify-app/notifications-test/comments/141012658' as Link,
         });
 
         nock('https://api.github.com')
@@ -168,7 +169,7 @@ describe('utils/subject.ts', () => {
         const mockNotification = partialMockNotification({
           title: 'This is a commit with comments',
           type: 'Commit',
-          url: 'https://api.github.com/repos/gitify-app/notifications-test/commits/d2a86d80e3d24ea9510d5de6c147e53c30f313a8',
+          url: 'https://api.github.com/repos/gitify-app/notifications-test/commits/d2a86d80e3d24ea9510d5de6c147e53c30f313a8' as Link,
           latest_comment_url: null,
         });
 
@@ -403,9 +404,9 @@ describe('utils/subject.ts', () => {
         mockNotification = partialMockNotification({
           title: 'This is a mock issue',
           type: 'Issue',
-          url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1',
+          url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1' as Link,
           latest_comment_url:
-            'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302888448',
+            'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302888448' as Link,
         });
       });
 
@@ -634,9 +635,9 @@ describe('utils/subject.ts', () => {
         mockNotification = partialMockNotification({
           title: 'This is a mock pull request',
           type: 'PullRequest',
-          url: 'https://api.github.com/repos/gitify-app/notifications-test/pulls/1',
+          url: 'https://api.github.com/repos/gitify-app/notifications-test/pulls/1' as Link,
           latest_comment_url:
-            'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302888448',
+            'https://api.github.com/repos/gitify-app/notifications-test/issues/comments/302888448' as Link,
         });
       });
 
@@ -1023,9 +1024,9 @@ describe('utils/subject.ts', () => {
         const mockNotification = partialMockNotification({
           title: 'This is a mock release',
           type: 'Release',
-          url: 'https://api.github.com/repos/gitify-app/notifications-test/releases/1',
+          url: 'https://api.github.com/repos/gitify-app/notifications-test/releases/1' as Link,
           latest_comment_url:
-            'https://api.github.com/repos/gitify-app/notifications-test/releases/1',
+            'https://api.github.com/repos/gitify-app/notifications-test/releases/1' as Link,
         });
 
         nock('https://api.github.com')
@@ -1109,7 +1110,7 @@ describe('utils/subject.ts', () => {
         const mockNotification = partialMockNotification({
           title: 'This issue will throw an error',
           type: 'Issue',
-          url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1',
+          url: 'https://api.github.com/repos/gitify-app/notifications-test/issues/1' as Link,
         });
 
         nock('https://api.github.com')
@@ -1292,7 +1293,7 @@ function mockDiscussionNode(
 ): Discussion {
   return {
     title: 'This is a mock discussion',
-    url: 'https://github.com/gitify-app/notifications-test/discussions/1',
+    url: 'https://github.com/gitify-app/notifications-test/discussions/1' as Link,
     stateReason: state,
     isAnswered: isAnswered,
     author: mockDiscussionAuthor,