diff --git a/djblets/static/djblets/js/configForms/models/listItemModel.ts b/djblets/static/djblets/js/configForms/models/listItemModel.ts
index 29e8057589846e8bc8d344eb5d308db036892490..2bbf809fdf2896ee359f54f37c3e6a2bafe745ac 100644
--- a/djblets/static/djblets/js/configForms/models/listItemModel.ts
+++ b/djblets/static/djblets/js/configForms/models/listItemModel.ts
@@ -13,10 +13,10 @@ import { BaseModel, ModelAttributes, spina } from '@beanbag/spina';
  */
 export interface ListItemAttrs extends ModelAttributes {
     /** Whether or not the model can be removed. */
-    canRemove: boolean;
+    canRemove?: boolean;
 
     /** The URL to edit the model. */
-    editURL: string;
+    editURL?: string;
 
     /**
      * A string representing the item's state.
@@ -24,13 +24,13 @@ export interface ListItemAttrs extends ModelAttributes {
      * This is used for those items that need to show an enabled, disabled,
      * error, or custom state.
      */
-    itemState: string;
+    itemState?: string;
 
     /** Whether or not the model is loading content from the server. */
-    loading: boolean;
+    loading?: boolean;
 
     /** The label for the "remove" action. */
-    removeLabel: string;
+    removeLabel?: string;
 
     /**
      * Whether or not the "remove" action should be present.
@@ -39,10 +39,10 @@ export interface ListItemAttrs extends ModelAttributes {
      * :js:attr:`actions` attribute will be pre-propulated with an action to
      * remove itself.
      */
-    showRemove: boolean;
+    showRemove?: boolean;
 
     /** The display name of the model. */
-    text: string;
+    text?: string;
 }
 
 
@@ -73,8 +73,33 @@ export interface ListItemAction {
      */
     danger?: boolean;
 
-    /** Whether the action is enabled. */
-    enabled: boolean;
+    /**
+     * Whether the action is enabled.
+     *
+     * This defaults to ``true``.
+     */
+    enabled?: boolean;
+
+    /**
+     * The name of the property on the model to bind the enabled state to.
+     */
+    enabledPropName?: string;
+
+    /**
+     * Whether to inverse the enabled state when binding enabledPropName.
+     *
+     * This defaults to ``false``.
+     */
+    enabledPropInverse?: boolean;
+
+    /**
+     * Whether to dispatch a click event when toggled on.
+     *
+     * This only applies to radio button actions.
+     *
+     * This defaults to ``false``.
+     */
+    dispatchOnClick?: boolean;
 
     /**
      * The name of the icon to display for the action, if any.
diff --git a/djblets/static/djblets/js/configForms/views/listItemView.ts b/djblets/static/djblets/js/configForms/views/listItemView.ts
index fd27f75c52da69de93563541ffa4f7c6686102c2..080eb0ebff795c33b2ba677a59ec412512ee3a98 100644
--- a/djblets/static/djblets/js/configForms/views/listItemView.ts
+++ b/djblets/static/djblets/js/configForms/views/listItemView.ts
@@ -2,6 +2,7 @@
  * Base view for displaying a list item in config pages.
  */
 import { BaseView, EventsHash, spina } from '@beanbag/spina';
+import * as _ from 'underscore';
 
 import { ListItem, ListItemAction } from '../models/listItemModel';
 
@@ -34,7 +35,9 @@ export class ListItemView<
 > extends BaseView<TModel, TElement, TExtraViewOptions> {
     static className = 'djblets-c-config-forms-list__item';
     static tagName = 'li';
+
     static iconBaseClassName = 'djblets-icon';
+    iconBaseClassName: string;
 
     /**
      * A mapping of item states to CSS classes.
@@ -47,6 +50,7 @@ export class ListItemView<
         enabled: '-is-enabled',
         error: '-has-error',
     };
+    itemStateClasses: { [key: string]: string };
 
     static template = _.template(dedent`
         <% if (editURL) { %>
@@ -55,8 +59,10 @@ export class ListItemView<
         <%- text %>
         <% } %>
     `);
+    template: _.CompiledTemplate;
 
     static actionHandlers: EventsHash = {};
+    actionHandlers: EventsHash;
 
     /**********************
      * Instance variables *
@@ -128,8 +134,10 @@ export class ListItemView<
      *
      * This will fade out the item, and then remove it from view.
      */
-    remove() {
+    remove(): this {
         this.$el.fadeOut('normal', () => super.remove());
+
+        return this;
     }
 
     /**
diff --git a/djblets/static/djblets/js/configForms/views/listView.ts b/djblets/static/djblets/js/configForms/views/listView.ts
index d7668355337da886aceed16456e6bbaa8533ec33..55e64530b80ba7391e7bf90f6a41f1fe61eb74fb 100644
--- a/djblets/static/djblets/js/configForms/views/listView.ts
+++ b/djblets/static/djblets/js/configForms/views/listView.ts
@@ -2,7 +2,9 @@
  * View for displaying a list of items.
  */
 
-import { BaseView, spina } from '@beanbag/spina';
+import { BaseView, Class, spina } from '@beanbag/spina';
+import type * as Backbone from 'Backbone';
+import * as _ from 'underscore';
 
 import { List } from '../models/listModel';
 import { ListItemView } from './listItemView';
@@ -16,7 +18,7 @@ import { ListItemView } from './listItemView';
  */
 export interface ListViewOptions {
     /** The item view class. */
-    ItemView: typeof Backbone.View;
+    ItemView?: typeof Backbone.View;
 
     /** Whether to animate added or removed items with a fade. */
     animateItems?: boolean;
@@ -56,7 +58,9 @@ export class ListView<
 > extends BaseView<TModel, TElement, TExtraViewOptions> {
     static className = 'djblets-c-config-forms-list';
     static tagName = 'ul';
-    static defaultItemView = ListItemView;
+
+    static defaultItemView: Class<ListItemView> = ListItemView;
+    defaultItemView: Class<ListItemView>;
 
     /**********************
      * Instance variables *
diff --git a/djblets/static/djblets/js/configForms/views/pagesView.ts b/djblets/static/djblets/js/configForms/views/pagesView.ts
index 77a9019b63b2477d18c139a7dc63987e15a4953f..25fc7ccf6ccf386f1b1247492087139dfa6e408c 100644
--- a/djblets/static/djblets/js/configForms/views/pagesView.ts
+++ b/djblets/static/djblets/js/configForms/views/pagesView.ts
@@ -3,6 +3,7 @@
  */
 
 import { BaseView, spina } from '@beanbag/spina';
+import * as Backbone from 'Backbone';
 
 
 /**
@@ -21,6 +22,16 @@ export class PagesView extends BaseView {
     /** The page router. */
     router: Backbone.Router;
 
+    /**
+     * All subpage navigation item elements.
+     */
+    _$pageNavs: JQuery;
+
+    /**
+     * All subpage elements on the page.
+     */
+    _$pages: JQuery;
+
     /** The active navigation item. */
     #$activeNav: JQuery;
 
diff --git a/djblets/static/djblets/js/configForms/views/tableItemView.ts b/djblets/static/djblets/js/configForms/views/tableItemView.ts
index 436ded701f3458c7b4d7fce1331a3883f0be899b..f314fede48e5dfd3aa47ed26a0345206157cfe24 100644
--- a/djblets/static/djblets/js/configForms/views/tableItemView.ts
+++ b/djblets/static/djblets/js/configForms/views/tableItemView.ts
@@ -3,6 +3,7 @@
  */
 
 import { spina } from '@beanbag/spina';
+import * as _ from 'underscore';
 
 import { ListItemView } from './listItemView';
 
diff --git a/djblets/static/djblets/js/configForms/views/tests/listItemViewTests.ts b/djblets/static/djblets/js/configForms/views/tests/listItemViewTests.ts
index 92f382028f5b4d37b01629e9a3bd62c29ee61b12..d8efd69980061ddc7e1affd3ffc785a0ab3a520e 100644
--- a/djblets/static/djblets/js/configForms/views/tests/listItemViewTests.ts
+++ b/djblets/static/djblets/js/configForms/views/tests/listItemViewTests.ts
@@ -1,9 +1,12 @@
 import {
+    beforeEach,
     describe,
     expect,
     it,
+    spyOn,
     suite,
 } from 'jasmine-core';
+import * as _ from 'underscore';
 
 import { ListItem } from '../../models/listItemModel';
 import { ListItemView } from '../listItemView';
@@ -22,7 +25,7 @@ suite('djblets/configForms/views/ListItemView', function() {
                 });
 
                 itemView.render();
-                expect(itemView.$el.html().strip()).toBe([
+                expect(itemView.$el.html().trim()).toBe([
                     '<span class="djblets-c-config-forms-list__item-actions">',
                     '</span>\n',
                     '<a href="http://example.com/">Label</a>',
@@ -38,7 +41,7 @@ suite('djblets/configForms/views/ListItemView', function() {
                 });
 
                 itemView.render();
-                expect(itemView.$el.html().strip()).toBe([
+                expect(itemView.$el.html().trim()).toBe([
                     '<span class="djblets-c-config-forms-list__item-actions">',
                     '</span>\n',
                     'Label',
diff --git a/djblets/static/djblets/js/configForms/views/tests/listViewTests.ts b/djblets/static/djblets/js/configForms/views/tests/listViewTests.ts
index 667ff547a8cfee692a5ad1d941a25dc4655e7e99..62beba153298943b098bdac13e8e1d643ef69ce2 100644
--- a/djblets/static/djblets/js/configForms/views/tests/listViewTests.ts
+++ b/djblets/static/djblets/js/configForms/views/tests/listViewTests.ts
@@ -5,6 +5,7 @@ import {
     it,
     suite,
 } from 'jasmine-core';
+import * as Backbone from 'Backbone';
 
 import { List } from '../../models/listModel';
 import { ListItem } from '../../models/listItemModel';
@@ -70,15 +71,20 @@ suite('djblets/configForms/views/ListView', () => {
                 expect(listView.$('button').length).toBe(0);
                 expect(listView.$('input').length).toBe(0);
             });
+        });
+    });
+
+    describe('Manages items', () => {
+        beforeEach(() => {
             listView.render();
         });
 
         it('On render', () => {
             const $items = listView.$('li');
             expect($items.length).toBe(3);
-            expect($items.eq(0).text().strip()).toBe('Item 1');
-            expect($items.eq(1).text().strip()).toBe('Item 2');
-            expect($items.eq(2).text().strip()).toBe('Item 3');
+            expect($items.eq(0).text().trim()).toBe('Item 1');
+            expect($items.eq(1).text().trim()).toBe('Item 2');
+            expect($items.eq(2).text().trim()).toBe('Item 3');
         });
 
         it('On add', () => {
@@ -88,7 +94,7 @@ suite('djblets/configForms/views/ListView', () => {
 
             const $items = listView.$('li');
             expect($items.length).toBe(4);
-            expect($items.eq(3).text().strip()).toBe('Item 4');
+            expect($items.eq(3).text().trim()).toBe('Item 4');
         });
 
         it('On remove', () => {
@@ -96,7 +102,7 @@ suite('djblets/configForms/views/ListView', () => {
 
             const $items = listView.$('li');
             expect($items.length).toBe(2);
-            expect($items.eq(0).text().strip()).toBe('Item 2');
+            expect($items.eq(0).text().trim()).toBe('Item 2');
         });
 
         it('On reset', () => {
@@ -107,8 +113,8 @@ suite('djblets/configForms/views/ListView', () => {
 
             const $items = listView.$('li');
             expect($items.length).toBe(2);
-            expect($items.eq(0).text().strip()).toBe('Foo');
-            expect($items.eq(1).text().strip()).toBe('Bar');
+            expect($items.eq(0).text().trim()).toBe('Foo');
+            expect($items.eq(1).text().trim()).toBe('Bar');
         });
     });
 });
diff --git a/tsconfig.json b/tsconfig.json
index ceb10a53e01715f63e91d0bdcb646ecebb96abc5..622f17b9c0fda5fd68c33380b5f13e93dd213d12 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -13,7 +13,7 @@
         ],
         "noEmit": true,
         "paths": {
-            "Backbone": ["node_modules/@beanbag/spina/lib/@types/backbone"],
+            "backbone": ["node_modules/@beanbag/spina/lib/@types/backbone"],
             "djblets/*": ["djblets/static/djblets/js/*"]
         },
         "target": "ESNext"
