diff --git a/packages/docs-app/src/examples/select-examples/multiSelectExample.tsx b/packages/docs-app/src/examples/select-examples/multiSelectExample.tsx
index ff5d0129c2..502f4ad7da 100644
--- a/packages/docs-app/src/examples/select-examples/multiSelectExample.tsx
+++ b/packages/docs-app/src/examples/select-examples/multiSelectExample.tsx
@@ -251,7 +251,9 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
         );
     }
 
-    private renderCustomTarget = (selectedItems: Film[]) => <MultiSelectCustomTarget count={selectedItems.length} />;
+    private renderCustomTarget = (selectedItems: readonly Film[]) => (
+        <MultiSelectCustomTarget count={selectedItems.length} />
+    );
 
     private renderTag = (film: Film) => film.title;
 
@@ -287,7 +289,7 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
         this.selectFilms([film]);
     }
 
-    private selectFilms(filmsToSelect: Film[]) {
+    private selectFilms(filmsToSelect: readonly Film[]) {
         this.setState(({ createdItems, films, items }) => {
             let nextCreatedItems = createdItems.slice();
             let nextFilms = films.slice();
@@ -336,7 +338,7 @@ export class MultiSelectExample extends React.PureComponent<ExampleProps, MultiS
         }
     };
 
-    private handleFilmsPaste = (films: Film[]) => {
+    private handleFilmsPaste = (films: readonly Film[]) => {
         // On paste, don't bother with deselecting already selected values, just
         // add the new ones.
         this.selectFilms(films);
diff --git a/packages/docs-app/src/examples/select-examples/selectExample.tsx b/packages/docs-app/src/examples/select-examples/selectExample.tsx
index 18759c67f5..e9fab83d2d 100644
--- a/packages/docs-app/src/examples/select-examples/selectExample.tsx
+++ b/packages/docs-app/src/examples/select-examples/selectExample.tsx
@@ -169,7 +169,7 @@ export class SelectExample extends React.PureComponent<ExampleProps, SelectExamp
         return /[0-9]/.test(firstLetter) ? "0-9" : firstLetter;
     }
 
-    private getGroupedItems = (filteredItems: Film[]) => {
+    private getGroupedItems = (filteredItems: readonly Film[]) => {
         return filteredItems.reduce<Array<{ group: string; index: number; items: Film[]; key: number }>>(
             (acc, item, index) => {
                 const group = this.getGroup(item);
@@ -193,7 +193,7 @@ export class SelectExample extends React.PureComponent<ExampleProps, SelectExamp
         ) : undefined;
     };
 
-    private groupedItemListPredicate = (query: string, items: Film[]) => {
+    private groupedItemListPredicate = (query: string, items: readonly Film[]) => {
         return items
             .filter((item, index) => filterFilm(query, item, index))
             .sort((a, b) => this.getGroup(a).localeCompare(this.getGroup(b)));
diff --git a/packages/docs-theme/src/components/navigator.tsx b/packages/docs-theme/src/components/navigator.tsx
index c6e69faf93..0c7eabdc3d 100644
--- a/packages/docs-theme/src/components/navigator.tsx
+++ b/packages/docs-theme/src/components/navigator.tsx
@@ -84,7 +84,7 @@ export class Navigator extends React.PureComponent<NavigatorProps> {
     }
 
     private filterMatches: ItemListPredicate<NavigationSection> = (query, items) =>
-        filter(items, query, {
+        filter(items.slice(), query, {
             key: "route",
             maxInners: items.length / 5,
             maxResults: 10,
diff --git a/packages/select/src/common/itemListRenderer.ts b/packages/select/src/common/itemListRenderer.ts
index 180f762fad..89c75aa580 100644
--- a/packages/select/src/common/itemListRenderer.ts
+++ b/packages/select/src/common/itemListRenderer.ts
@@ -35,13 +35,13 @@ export interface ItemListRendererProps<T> {
      * map each item in this array through `renderItem`, with support for
      * optional `noResults` and `initialContent` states.
      */
-    filteredItems: T[];
+    filteredItems: readonly T[];
 
     /**
      * Array of all items in the list.
      * See `filteredItems` for a filtered array based on `query` and predicate props.
      */
-    items: T[];
+    items: readonly T[];
 
     /**
      * The current query string.
diff --git a/packages/select/src/common/listItemsProps.ts b/packages/select/src/common/listItemsProps.ts
index 2beb4431b3..433bd5cd17 100644
--- a/packages/select/src/common/listItemsProps.ts
+++ b/packages/select/src/common/listItemsProps.ts
@@ -44,7 +44,7 @@ export interface ListItemsProps<T> extends Props {
     activeItem?: T | CreateNewItem | null;
 
     /** Array of items in the list. */
-    items: T[];
+    items: readonly T[];
 
     /**
      * Specifies how to test if two items are equal. By default, simple strict
@@ -157,7 +157,7 @@ export interface ListItemsProps<T> extends Props {
     /**
      * Callback invoked when multiple items are selected at once via pasting.
      */
-    onItemsPaste?: (items: T[]) => void;
+    onItemsPaste?: (items: readonly T[]) => void;
 
     /**
      * Callback invoked when the query string changes.
diff --git a/packages/select/src/common/predicate.ts b/packages/select/src/common/predicate.ts
index 8011cbe033..af16229b71 100644
--- a/packages/select/src/common/predicate.ts
+++ b/packages/select/src/common/predicate.ts
@@ -18,7 +18,7 @@
  * A custom predicate for returning an entirely new `items` array based on the provided query.
  * See usage sites in `ListItemsProps`.
  */
-export type ItemListPredicate<T> = (query: string, items: T[]) => T[];
+export type ItemListPredicate<T> = (query: string, items: readonly T[]) => readonly T[];
 
 /**
  * A custom predicate for filtering items based on the provided query.
diff --git a/packages/select/src/components/multi-select/multiSelect.tsx b/packages/select/src/components/multi-select/multiSelect.tsx
index c1be8deeae..bd4e933ac1 100644
--- a/packages/select/src/components/multi-select/multiSelect.tsx
+++ b/packages/select/src/components/multi-select/multiSelect.tsx
@@ -44,7 +44,7 @@ export interface MultiSelectProps<T> extends ListItemsProps<T>, SelectPopoverPro
      * Element which triggers the multiselect popover. Providing this prop will replace the default TagInput
      * target thats rendered and move the search functionality to within the Popover.
      */
-    customTarget?: (selectedItems: T[], isOpen: boolean) => React.ReactNode;
+    customTarget?: (selectedItems: readonly T[], isOpen: boolean) => React.ReactNode;
 
     /**
      * Whether the component is non-interactive.
@@ -104,7 +104,7 @@ export interface MultiSelectProps<T> extends ListItemsProps<T>, SelectPopoverPro
     placeholder?: string;
 
     /** Controlled selected values. */
-    selectedItems: T[];
+    selectedItems: readonly T[];
 
     /**
      * Props to pass to the [TagInput component](##core/components/tag-input).
diff --git a/packages/select/src/components/query-list/queryList.tsx b/packages/select/src/components/query-list/queryList.tsx
index e326843711..a6ff0bc87f 100644
--- a/packages/select/src/components/query-list/queryList.tsx
+++ b/packages/select/src/components/query-list/queryList.tsx
@@ -137,7 +137,7 @@ export interface QueryListState<T> {
     createNewItem: T | T[] | undefined;
 
     /** The original `items` array filtered by `itemListPredicate` or `itemPredicate`. */
-    filteredItems: T[];
+    filteredItems: readonly T[];
 
     /** The current query string. */
     query: string;
@@ -676,7 +676,7 @@ function isItemDisabled<T>(item: T | null, index: number, itemDisabled?: ListIte
  * @param startIndex which index to begin moving from
  */
 export function getFirstEnabledItem<T>(
-    items: T[],
+    items: readonly T[],
     itemDisabled?: keyof T | ((item: T, index: number) => boolean),
     direction = 1,
     startIndex = items.length - 1,
diff --git a/packages/select/test/queryListTests.tsx b/packages/select/test/queryListTests.tsx
index 87dccf112d..4783606988 100644
--- a/packages/select/test/queryListTests.tsx
+++ b/packages/select/test/queryListTests.tsx
@@ -82,7 +82,9 @@ describe("<QueryList>", () => {
         });
 
         it("itemListPredicate filters entire list by query", () => {
-            const predicate = sinon.spy((query: string, films: Film[]) => films.filter(f => f.year === +query));
+            const predicate = sinon.spy((query: string, films: readonly Film[]) =>
+                films.filter(f => f.year === +query),
+            );
             shallow(<QueryList<Film> {...testProps} itemListPredicate={predicate} query="1994" />);
 
             assert.equal(predicate.callCount, 1, "called once for entire list");