TypeCheck Frontend (#2394)

We recently had an error that would've been caught by type checking in the frontend (see #2393). This PR implements type checking so that future errors will be caught.

Additionally, this PR contains miscellaneous frontend cleanup that's tangentially related to type-checking.
This commit is contained in:
Sam Freund
2026-05-05 10:24:19 -05:00
committed by GitHub
parent d587cd19bb
commit 2372e110f9
43 changed files with 578 additions and 388 deletions

View File

@@ -1,13 +1,15 @@
<script setup lang="ts">
<script setup lang="ts" generic="T extends string | number">
import { computed } from "vue";
import TooltippedLabel from "@/components/common/pv-tooltipped-label.vue";
export interface SelectItem {
export interface SelectItem<TValue extends string | number> {
name: string | number;
value: string | number;
value: TValue;
disabled?: boolean;
}
const value = defineModel<string | number | undefined>({ required: true });
type SelectItems = SelectItem<T>[] | ReadonlyArray<T>;
const value = defineModel<T>({ required: true });
const props = withDefaults(
defineProps<{
@@ -15,7 +17,7 @@ const props = withDefaults(
tooltip?: string;
selectCols?: number;
disabled?: boolean;
items: string[] | number[] | SelectItem[];
items: SelectItems;
}>(),
{
selectCols: 9,
@@ -23,18 +25,20 @@ const props = withDefaults(
}
);
const areSelectItems = (items: SelectItems): items is SelectItem<T>[] => typeof items[0] === "object";
// Computed in case items changes
const items = computed<SelectItem[]>(() => {
const items = computed<SelectItem<T>[]>(() => {
// Trivial case for empty list; we have no data
if (!props.items.length) {
return [];
}
// Check if the prop exists on the object to infer object type
if ((props.items[0] as SelectItem).name) {
return props.items as SelectItem[];
if (areSelectItems(props.items)) {
return props.items;
}
return props.items.map((v, i) => ({ name: v, value: i }));
return props.items.map((item) => ({ name: item, value: item }));
});
</script>
@@ -49,7 +53,7 @@ const items = computed<SelectItem[]>(() => {
:items="items"
item-title="name"
item-value="value"
item-props.disabled="disabled"
item-props
:disabled="disabled"
hide-details="auto"
variant="underlined"