diff --git a/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.jsx b/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.tsx
similarity index 64%
rename from enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.jsx
rename to enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.tsx
index 27b494827d0cfa98c968120eafbce7b4e8332cee..b94e11aa135bb8ae5c2acc20c29cea032bdf1f74 100644
--- a/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.jsx
+++ b/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.tsx
@@ -1,52 +1,44 @@
-import PropTypes from "prop-types";
 import { connect } from "react-redux";
 import _ from "underscore";
 
 import Users from "metabase/entities/users";
-import { color, alpha } from "metabase/lib/colors";
+import { alpha, color } from "metabase/lib/colors";
 import { getRelativeTime } from "metabase/lib/time";
 import { getUser } from "metabase/selectors/user";
 import { Icon } from "metabase/ui";
 import {
-  getTextForReviewBanner,
   getIconForReview,
+  getTextForReviewBanner,
 } from "metabase-enterprise/moderation/service";
+import type { ModerationReview, User } from "metabase-types/api";
 
 import {
   Container,
   Text,
-  Time,
   TextContainer,
+  Time,
 } from "./ModerationReviewBanner.styled";
 
 const ICON_BUTTON_SIZE = 16;
 
-const mapStateToProps = (state, props) => ({
+const mapStateToProps = (state: any, _props: any) => ({
   currentUser: getUser(state),
 });
 
-export default _.compose(
-  Users.load({
-    id: (state, props) => props.moderationReview.moderator_id,
-    loadingAndErrorWrapper: false,
-  }),
-  connect(mapStateToProps),
-)(ModerationReviewBanner);
-
-ModerationReviewBanner.propTypes = {
-  moderationReview: PropTypes.object.isRequired,
-  user: PropTypes.object,
-  currentUser: PropTypes.object.isRequired,
-  onRemove: PropTypes.func,
-  className: PropTypes.func,
-};
+interface ModerationReviewBannerProps {
+  moderationReview: ModerationReview;
+  user?: User | null;
+  currentUser: User;
+  onRemove?: () => void;
+  className?: string;
+}
 
-export function ModerationReviewBanner({
+export const ModerationReviewBanner = ({
   moderationReview,
-  user: moderator,
+  user: moderator = null,
   currentUser,
   className,
-}) {
+}: ModerationReviewBannerProps) => {
   const { bannerText } = getTextForReviewBanner(
     moderationReview,
     moderator,
@@ -57,7 +49,10 @@ export function ModerationReviewBanner({
     getIconForReview(moderationReview);
 
   return (
-    <Container backgroundColor={alpha(iconColor, 0.2)} className={className}>
+    <Container
+      style={{ backgroundColor: alpha(iconColor, 0.2) }}
+      className={className}
+    >
       <Icon name={iconName} color={color(iconColor)} size={ICON_BUTTON_SIZE} />
       <TextContainer>
         <Text>{bannerText}</Text>
@@ -67,4 +62,13 @@ export function ModerationReviewBanner({
       </TextContainer>
     </Container>
   );
-}
+};
+
+// eslint-disable-next-line import/no-default-export -- deprecated usage
+export default _.compose(
+  Users.load({
+    id: (_state: any, props: any) => props.moderationReview.moderator_id,
+    loadingAndErrorWrapper: false,
+  }),
+  connect(mapStateToProps),
+)(ModerationReviewBanner);
diff --git a/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.unit.spec.js b/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.unit.spec.tsx
similarity index 59%
rename from enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.unit.spec.js
rename to enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.unit.spec.tsx
index ae7fb2bb3372c5720a03d3fc0daffe60acdceeab..1f66f13cff2ae3ad3ed7912dd6364c2bc3bfcb68 100644
--- a/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.unit.spec.js
+++ b/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationReviewBanner/ModerationReviewBanner.unit.spec.tsx
@@ -1,14 +1,17 @@
 import { render, screen } from "@testing-library/react";
 
+import type { ModerationReview, User } from "metabase-types/api";
+import { createMockUser } from "metabase-types/api/mocks";
+
 import { ModerationReviewBanner } from "./ModerationReviewBanner";
 
-const moderationReview = {
+const moderationReview: ModerationReview = {
   status: "verified",
   moderator_id: 1,
-  created_at: Date.now(),
+  created_at: Date.now().toString(),
 };
-const moderator = { id: 1, common_name: "Foo" };
-const currentUser = { id: 2, common_name: "Bar" };
+const moderator: User = createMockUser({ id: 1, common_name: "Foo" });
+const currentUser: User = createMockUser({ id: 2, common_name: "Bar" });
 
 describe("ModerationReviewBanner", () => {
   it("should show text concerning the given review", () => {
diff --git a/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationStatusIcon/ModerationStatusIcon.tsx b/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationStatusIcon/ModerationStatusIcon.tsx
index 5872ded3638eaee3060790994e3e951b98814d68..80e5f7c4675347658efdf8d79476a14fe842924c 100644
--- a/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationStatusIcon/ModerationStatusIcon.tsx
+++ b/enterprise/frontend/src/metabase-enterprise/moderation/components/ModerationStatusIcon/ModerationStatusIcon.tsx
@@ -1,6 +1,6 @@
 import { color } from "metabase/lib/colors";
 import type { IconProps } from "metabase/ui";
-import { Icon } from "metabase/ui";
+import { FixedSizeIcon } from "metabase/ui";
 import { getStatusIcon } from "metabase-enterprise/moderation/service";
 
 type ModerationStatusIconProps = {
@@ -13,8 +13,25 @@ export const ModerationStatusIcon = ({
   filled = false,
   ...iconProps
 }: ModerationStatusIconProps) => {
-  const { name: iconName, color: iconColor } = getStatusIcon(status, filled);
-  return iconName ? (
-    <Icon name={iconName} color={color(iconColor)} {...iconProps} />
-  ) : null;
+  const { name: iconName, color: iconColor } = getStatusIcon(
+    status ?? null,
+    filled,
+  );
+  if (!iconName) {
+    return null;
+  }
+  const reformattedIconProps = {
+    ...iconProps,
+    size:
+      typeof iconProps.size === "string"
+        ? parseInt(iconProps.size)
+        : iconProps.size,
+  };
+  return (
+    <FixedSizeIcon
+      name={iconName}
+      color={color(iconColor)}
+      {...reformattedIconProps}
+    />
+  );
 };
diff --git a/enterprise/frontend/src/metabase-enterprise/moderation/constants.js b/enterprise/frontend/src/metabase-enterprise/moderation/constants.js
deleted file mode 100644
index 4b56960553e9daf94177fafa05386c7b25798d0b..0000000000000000000000000000000000000000
--- a/enterprise/frontend/src/metabase-enterprise/moderation/constants.js
+++ /dev/null
@@ -1,18 +0,0 @@
-export const MODERATION_STATUS = {
-  verified: "verified",
-};
-
-export const MODERATION_STATUS_ICONS = {
-  verified: {
-    name: "verified",
-    color: "brand",
-  },
-  verified_filled: {
-    name: "verified_filled",
-    color: "brand",
-  },
-  null: {
-    name: "close",
-    color: "text-light",
-  },
-};
diff --git a/enterprise/frontend/src/metabase-enterprise/moderation/constants.ts b/enterprise/frontend/src/metabase-enterprise/moderation/constants.ts
new file mode 100644
index 0000000000000000000000000000000000000000..07beaa5291fa142d74d7ea8aeab2759ca3ab337b
--- /dev/null
+++ b/enterprise/frontend/src/metabase-enterprise/moderation/constants.ts
@@ -0,0 +1,26 @@
+import type { ColorName } from "metabase/lib/colors/types";
+import type { IconName } from "metabase/ui";
+
+export const MODERATION_STATUS = {
+  verified: "verified",
+};
+
+export const MODERATION_STATUS_ICONS: Map<
+  string | null,
+  { name: IconName; color: ColorName }
+> = new Map();
+
+MODERATION_STATUS_ICONS.set("verified", {
+  name: "verified",
+  color: "brand",
+});
+
+MODERATION_STATUS_ICONS.set("verified_filled", {
+  name: "verified_filled",
+  color: "brand",
+});
+
+MODERATION_STATUS_ICONS.set(null, {
+  name: "close",
+  color: "text-light",
+});
diff --git a/enterprise/frontend/src/metabase-enterprise/moderation/service.js b/enterprise/frontend/src/metabase-enterprise/moderation/service.js
deleted file mode 100644
index b63595ad9ca3cecb749c7979e4714c1f8c79915c..0000000000000000000000000000000000000000
--- a/enterprise/frontend/src/metabase-enterprise/moderation/service.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import { t } from "ttag";
-import _ from "underscore";
-
-import { ModerationReviewApi } from "metabase/services";
-
-import { MODERATION_STATUS_ICONS } from "./constants";
-
-export { MODERATION_STATUS } from "./constants";
-
-export function verifyItem({ text, itemId, itemType }) {
-  return ModerationReviewApi.create({
-    status: "verified",
-    moderated_item_id: itemId,
-    moderated_item_type: itemType,
-    text,
-  });
-}
-
-export function removeReview({ itemId, itemType }) {
-  return ModerationReviewApi.create({
-    status: null,
-    moderated_item_id: itemId,
-    moderated_item_type: itemType,
-  });
-}
-
-const noIcon = {};
-
-export function getStatusIcon(status, filled = false) {
-  if (isRemovedReviewStatus(status)) {
-    return noIcon;
-  }
-
-  if (status === "verified" && filled) {
-    return MODERATION_STATUS_ICONS[`${status}_filled`];
-  }
-
-  return MODERATION_STATUS_ICONS[status] || noIcon;
-}
-
-export function getIconForReview(review, options) {
-  return getStatusIcon(review?.status, options);
-}
-
-// we only want the icon that represents the removal of a review in special cases,
-// so you must ask for the icon explicitly
-export function getRemovedReviewStatusIcon() {
-  return MODERATION_STATUS_ICONS[null];
-}
-
-export function getLatestModerationReview(reviews) {
-  const maybeReview = _.findWhere(reviews, {
-    most_recent: true,
-  });
-
-  // since we can't delete reviews, consider a most recent review with a status of null to mean there is no review
-  return isRemovedReviewStatus(maybeReview?.status) ? undefined : maybeReview;
-}
-
-export function getStatusIconForQuestion(question) {
-  const reviews = question.getModerationReviews();
-  const review = getLatestModerationReview(reviews);
-  return getIconForReview(review);
-}
-
-export function getTextForReviewBanner(
-  moderationReview,
-  moderator,
-  currentUser,
-) {
-  const { status } = moderationReview;
-
-  if (status === "verified") {
-    const bannerText = getModeratorDisplayText(moderator, currentUser);
-    const tooltipText = t`Remove verification`;
-    return { bannerText, tooltipText };
-  }
-
-  return {};
-}
-
-export function getModeratorDisplayName(moderator, currentUser) {
-  const { id: moderatorId, common_name } = moderator || {};
-  const { id: currentUserId } = currentUser || {};
-
-  if (currentUserId != null && moderatorId === currentUserId) {
-    return t`You`;
-  } else if (moderatorId != null) {
-    return common_name;
-  } else {
-    return t`A moderator`;
-  }
-}
-
-export function getModeratorDisplayText(moderator, currentUser) {
-  const moderatorName = getModeratorDisplayName(moderator, currentUser);
-  return t`${moderatorName} verified this`;
-}
-
-// a `status` of `null` represents the removal of a review, since we can't delete reviews
-export function isRemovedReviewStatus(status) {
-  return String(status) === "null";
-}
-
-export function isItemVerified(review) {
-  return review != null && review.status === "verified";
-}
-
-function getModerationReviewEventText(review, moderatorDisplayName) {
-  switch (review.status) {
-    case "verified":
-      return t`${moderatorDisplayName} verified this`;
-    case null:
-      return t`${moderatorDisplayName} removed verification`;
-    default:
-      return t`${moderatorDisplayName} changed status to ${review.status}`;
-  }
-}
-
-export function getModerationTimelineEvents(reviews, usersById, currentUser) {
-  return reviews.map(review => {
-    const moderator = usersById[review.moderator_id];
-    const moderatorDisplayName = getModeratorDisplayName(
-      moderator,
-      currentUser,
-    );
-    const text = getModerationReviewEventText(review, moderatorDisplayName);
-    const icon = isRemovedReviewStatus(review.status)
-      ? getRemovedReviewStatusIcon()
-      : getIconForReview(review);
-
-    return {
-      timestamp: new Date(review.created_at).toISOString(),
-      icon,
-      title: text,
-    };
-  });
-}
-
-export const getQuestionIcon = card => {
-  return (card.model === "dataset" || card.type === "model") &&
-    card.moderated_status === "verified"
-    ? { icon: "model_with_badge", tooltip: "Verified model" }
-    : null;
-};
diff --git a/enterprise/frontend/src/metabase-enterprise/moderation/service.ts b/enterprise/frontend/src/metabase-enterprise/moderation/service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c169977de3d49608d665d7fe7f098c0d3b6fd782
--- /dev/null
+++ b/enterprise/frontend/src/metabase-enterprise/moderation/service.ts
@@ -0,0 +1,192 @@
+import { c, t } from "ttag";
+import _ from "underscore";
+
+import type { ColorName } from "metabase/lib/colors/types";
+import { ModerationReviewApi } from "metabase/services";
+import type { IconName } from "metabase/ui";
+import type Question from "metabase-lib/v1/Question";
+import type { ModerationReview, User } from "metabase-types/api";
+
+import { MODERATION_STATUS_ICONS } from "./constants";
+
+export { MODERATION_STATUS } from "./constants";
+
+export function verifyItem({
+  text,
+  itemId,
+  itemType,
+}: {
+  text: string;
+  itemId: number;
+  itemType: string;
+}) {
+  return ModerationReviewApi.create({
+    status: "verified",
+    moderated_item_id: itemId,
+    moderated_item_type: itemType,
+    text,
+  });
+}
+
+export function removeReview({
+  itemId,
+  itemType,
+}: {
+  itemId: number;
+  itemType: string;
+}) {
+  return ModerationReviewApi.create({
+    status: null,
+    moderated_item_id: itemId,
+    moderated_item_type: itemType,
+  });
+}
+
+type NoIcon = Record<string, never>;
+
+const noIcon: NoIcon = {};
+
+export const getStatusIcon = (
+  status: string | null | undefined,
+  filled = false,
+): { name: IconName; color: ColorName } | NoIcon => {
+  if (!status || isRemovedReviewStatus(status)) {
+    return noIcon;
+  }
+
+  if (status === "verified" && filled) {
+    return MODERATION_STATUS_ICONS.get("verified_filled") || noIcon;
+  }
+
+  return MODERATION_STATUS_ICONS.get(status) || noIcon;
+};
+
+export function getIconForReview(review: ModerationReview, options?: any) {
+  return getStatusIcon(review?.status, options);
+}
+
+// we only want the icon that represents the removal of a review in special cases,
+// so you must ask for the icon explicitly
+export function getRemovedReviewStatusIcon() {
+  return MODERATION_STATUS_ICONS.get(null);
+}
+
+export function getLatestModerationReview(reviews: ModerationReview[]) {
+  const maybeReview = _.findWhere(reviews, {
+    most_recent: true,
+  });
+  if (!maybeReview) {
+    return undefined;
+  }
+  // since we can't delete reviews, consider a most recent review with a status of null to mean there is no review
+  return isRemovedReviewStatus(maybeReview.status) ? undefined : maybeReview;
+}
+
+export const getStatusIconForQuestion = (question: Question) => {
+  const reviews = question.getModerationReviews();
+  const review = getLatestModerationReview(reviews);
+  return review ? getIconForReview(review) : noIcon;
+};
+
+export const getTextForReviewBanner = (
+  moderationReview: ModerationReview,
+  moderator: User | null,
+  currentUser: User | null,
+) => {
+  const { status } = moderationReview;
+
+  if (status === "verified") {
+    const bannerText = getModeratorDisplayText(moderator, currentUser);
+    const tooltipText = t`Remove verification`;
+    return { bannerText, tooltipText };
+  }
+
+  return {};
+};
+
+export const getModeratorDisplayName = (
+  moderator: User | null,
+  currentUser?: User | null,
+) => {
+  const { id: moderatorId, common_name } = moderator || {};
+  const { id: currentUserId } = currentUser || {};
+
+  if (currentUserId != null && moderatorId === currentUserId) {
+    return t`You`;
+  } else if (moderatorId != null && common_name) {
+    return common_name;
+  } else {
+    return t`A moderator`;
+  }
+};
+
+export const getModeratorDisplayText = (
+  moderator: User | null,
+  currentUser: User | null,
+) => {
+  const moderatorName = getModeratorDisplayName(moderator, currentUser);
+  return c("{0} is the name of a user").t`${moderatorName} verified this`;
+};
+
+// a `status` of `null` represents the removal of a review, since we can't delete reviews
+export const isRemovedReviewStatus = (status: string | null) => {
+  return status === null;
+};
+
+export const isItemVerified = (
+  review?: ModerationReview | undefined | null,
+) => {
+  return review != null && review.status === "verified";
+};
+
+const getModerationReviewEventText = (
+  review: ModerationReview,
+  moderatorDisplayName: string,
+) => {
+  switch (review.status) {
+    case "verified":
+      return c("{0} is the name of a user")
+        .t`${moderatorDisplayName} verified this`;
+    case null:
+      return c("{0} is the name of a user")
+        .t`${moderatorDisplayName} removed verification`;
+    default:
+      return c("{0} is the name of a user, {1} is the status of a review")
+        .t`${moderatorDisplayName} changed status to ${review.status}`;
+  }
+};
+
+export function getModerationTimelineEvents(
+  reviews: ModerationReview[],
+  usersById: Record<number, User>,
+  currentUser?: User,
+) {
+  return reviews.map(review => {
+    const moderator = review.moderator_id
+      ? usersById[review.moderator_id]
+      : null;
+    const moderatorDisplayName = getModeratorDisplayName(
+      moderator,
+      currentUser,
+    );
+    const text = getModerationReviewEventText(review, moderatorDisplayName);
+    const icon = isRemovedReviewStatus(review.status)
+      ? getRemovedReviewStatusIcon()
+      : getIconForReview(review);
+
+    return {
+      timestamp: review.created_at
+        ? new Date(review.created_at).toISOString()
+        : null,
+      icon,
+      title: text,
+    };
+  });
+}
+
+export const getQuestionIcon = (card: any) => {
+  return (card.model === "dataset" || card.type === "model") &&
+    card.moderated_status === "verified"
+    ? { icon: "model_with_badge" as IconName, tooltip: "Verified model" }
+    : null;
+};
diff --git a/enterprise/frontend/src/metabase-enterprise/moderation/service.unit.spec.js b/enterprise/frontend/src/metabase-enterprise/moderation/service.unit.spec.ts
similarity index 70%
rename from enterprise/frontend/src/metabase-enterprise/moderation/service.unit.spec.js
rename to enterprise/frontend/src/metabase-enterprise/moderation/service.unit.spec.ts
index 11a0c2a6b15c3035129e39d414dd981e2168c257..ead73bcefa66df503fd0ed97ce4c7d51074ec40f 100644
--- a/enterprise/frontend/src/metabase-enterprise/moderation/service.unit.spec.js
+++ b/enterprise/frontend/src/metabase-enterprise/moderation/service.unit.spec.ts
@@ -1,4 +1,10 @@
 import { ModerationReviewApi } from "metabase/services";
+import type Question from "metabase-lib/v1/Question";
+import type { ModerationReview, User } from "metabase-types/api";
+import {
+  createMockModerationReview,
+  createMockUser,
+} from "metabase-types/api/mocks";
 
 import {
   verifyItem,
@@ -93,15 +99,21 @@ describe("moderation/service", () => {
 
   describe("getIconForReview", () => {
     it("should return icon name/color for given review", () => {
-      expect(getIconForReview({ status: "verified" })).toEqual(
-        getStatusIcon("verified"),
-      );
+      expect(
+        getIconForReview(createMockModerationReview({ status: "verified" })),
+      ).toEqual(getStatusIcon("verified"));
     });
   });
 
   describe("getTextForReviewBanner", () => {
     it("should return text for a verified review", () => {
-      expect(getTextForReviewBanner({ status: "verified" })).toEqual({
+      expect(
+        getTextForReviewBanner(
+          createMockModerationReview({ status: "verified" }),
+          null,
+          null,
+        ),
+      ).toEqual({
         bannerText: "A moderator verified this",
         tooltipText: "Remove verification",
       });
@@ -110,12 +122,12 @@ describe("moderation/service", () => {
     it("should include the moderator name", () => {
       expect(
         getTextForReviewBanner(
-          { status: "verified" },
-          {
+          createMockModerationReview({ status: "verified" }),
+          createMockUser({
             common_name: "Foo",
             id: 1,
-          },
-          { id: 2 },
+          }),
+          createMockUser({ id: 2 }),
         ),
       ).toEqual({
         bannerText: "Foo verified this",
@@ -126,12 +138,12 @@ describe("moderation/service", () => {
     it("should handle the moderator being the current user", () => {
       expect(
         getTextForReviewBanner(
-          { status: "verified" },
-          {
+          createMockModerationReview({ status: "verified" }),
+          createMockUser({
             common_name: "Foo",
             id: 1,
-          },
-          { id: 1 },
+          }),
+          createMockUser({ id: 1 }),
         ),
       ).toEqual({
         bannerText: "You verified this",
@@ -142,11 +154,15 @@ describe("moderation/service", () => {
 
   describe("isItemVerified", () => {
     it("should return true for a verified review", () => {
-      expect(isItemVerified({ status: "verified" })).toBe(true);
+      expect(
+        isItemVerified(createMockModerationReview({ status: "verified" })),
+      ).toBe(true);
     });
 
     it("should return false for a null review", () => {
-      expect(isItemVerified({ status: null })).toBe(false);
+      expect(isItemVerified(createMockModerationReview({ status: null }))).toBe(
+        false,
+      );
     });
 
     it("should return false for no review", () => {
@@ -156,24 +172,30 @@ describe("moderation/service", () => {
 
   describe("getLatestModerationReview", () => {
     it("should return the review flagged as most recent", () => {
-      const reviews = [
-        { id: 1, status: "verified" },
-        { id: 2, status: "verified", most_recent: true },
-        { id: 3, status: null },
+      const reviews: ModerationReview[] = [
+        { moderator_id: 0, created_at: "", status: "verified" },
+        {
+          moderator_id: 0,
+          created_at: "",
+          status: "verified",
+          most_recent: true,
+        },
+        { moderator_id: 0, created_at: "", status: null },
       ];
 
       expect(getLatestModerationReview(reviews)).toEqual({
-        id: 2,
+        moderator_id: 0,
+        created_at: "",
         status: "verified",
         most_recent: true,
       });
     });
 
     it("should return undefined when there is no review flagged as most recent", () => {
-      const reviews = [
-        { id: 1, status: "verified" },
-        { id: 2, status: "verified" },
-        { id: 3, status: null },
+      const reviews: ModerationReview[] = [
+        { moderator_id: 0, created_at: "", status: "verified" },
+        { moderator_id: 0, created_at: "", status: "verified" },
+        { moderator_id: 0, created_at: "", status: null },
       ];
 
       expect(getLatestModerationReview(reviews)).toEqual(undefined);
@@ -181,10 +203,10 @@ describe("moderation/service", () => {
     });
 
     it("should return undefined when there is a review with a status of null flagged as most recent", () => {
-      const reviews = [
-        { id: 1, status: "verified" },
-        { id: 2, status: "verified" },
-        { id: 3, status: null, most_recent: true },
+      const reviews: ModerationReview[] = [
+        { moderator_id: 0, created_at: "", status: "verified" },
+        { moderator_id: 0, created_at: "", status: "verified" },
+        { moderator_id: 0, created_at: "", status: null, most_recent: true },
       ];
 
       expect(getLatestModerationReview(reviews)).toEqual(undefined);
@@ -199,31 +221,34 @@ describe("moderation/service", () => {
           { id: 2, status: "verified", most_recent: true },
           { id: 3, status: null },
         ],
-      };
-
-      expect(getStatusIconForQuestion(questionWithReviews)).toEqual(
-        getStatusIcon("verified"),
-      );
+      } as unknown as Question;
+
+      const { color: actualColor, name: actualName } =
+        getStatusIconForQuestion(questionWithReviews) || {};
+      const { color: expectedColor, name: expectedName } =
+        getStatusIcon("verified");
+      expect(expectedColor).toEqual(actualColor);
+      expect(expectedName).toEqual(actualName);
     });
 
     it("should return undefined vals for no review", () => {
       const questionWithNoMostRecentReview = {
         getModerationReviews: () => [
-          { id: 1, status: "verified" },
-          { id: 2, status: "verified" },
-          { id: 3, status: null, most_recent: true },
+          { moderator_id: 0, created_at: "", status: "verified" },
+          { moderator_id: 0, created_at: "", status: "verified" },
+          { moderator_id: 0, created_at: "", status: null, most_recent: true },
         ],
-      };
+      } as unknown as Question;
 
       const questionWithNoReviews = {
         getModerationReviews: () => [],
-      };
+      } as unknown as Question;
 
       const questionWithUndefinedReviews = {
         getModerationReviews: () => undefined,
-      };
+      } as unknown as Question;
 
-      const noIcon = { name: undefined, color: undefined };
+      const noIcon = {};
 
       expect(getStatusIconForQuestion(questionWithNoMostRecentReview)).toEqual(
         noIcon,
@@ -237,25 +262,23 @@ describe("moderation/service", () => {
 
   describe("getModerationTimelineEvents", () => {
     it("should return the moderation timeline events", () => {
-      const reviews = [
+      const reviews: ModerationReview[] = [
         {
-          id: 1,
           status: "verified",
           created_at: "2018-01-01T00:00:00.000Z",
           moderator_id: 1,
         },
         {
-          id: 2,
           status: null,
           created_at: "2018-01-02T00:00:00.000Z",
           moderator_id: 123,
         },
       ];
-      const usersById = {
-        1: {
+      const usersById: Record<number, User> = {
+        1: createMockUser({
           id: 1,
           common_name: "Foo",
-        },
+        }),
       };
 
       expect(getModerationTimelineEvents(reviews, usersById)).toEqual([
diff --git a/frontend/src/metabase-types/api/card.ts b/frontend/src/metabase-types/api/card.ts
index 650fbaee37cf69f441f1c80f7cf06877b7106cee..85c161f8487ce44ebb6c03a753ae8f310cd2008a 100644
--- a/frontend/src/metabase-types/api/card.ts
+++ b/frontend/src/metabase-types/api/card.ts
@@ -196,14 +196,14 @@ export type VisualizationSettings = {
 };
 
 export interface ModerationReview {
+  status: ModerationReviewStatus;
   moderator_id: number;
-  status: ModerationReviewStatus | null;
   created_at: string;
-  most_recent: boolean;
+  most_recent?: boolean;
 }
 
 export type CardId = number;
-export type ModerationReviewStatus = "verified";
+export type ModerationReviewStatus = "verified" | null;
 
 export type CardFilterOption =
   | "all"