Import DataTableHeader typescript type of Vuetify3 v-data-table
Asked Answered
D

3

7

I cannot import the type definition DataTableHeader for v-data-table headers. Currently, I have written it like this:

import { DataTableHeader } from 'vuetify/types';

In the TypeScript error, it says

Cannot find module 'vuetify/types' or its corresponding type declarations.

Does anyone know a solution to this problem?

Dennis answered 12/4, 2023 at 2:8 Comment(0)
D
36

The DataTableHeaders type is currently not exported (as of Vuetify 3.5.5). My guess is that this will change in the future, but in the meantime, you can still extract it from the VDataTable.

Vuetify 3.5 (current)

Since v3.3, headers are deep readonly. We can undo the readonly, but not without changing the type, which makes it incompatible with the initial DataTableHeader declaration and requires an additional type assertion when assigning to the v-data-table.

So if you know you won't change the headers after declaration, I would just use the readonly declaration:

import type { VDataTable } from 'vuetify/components'

type ReadonlyHeaders = VDataTable['$props']['headers']

const headers: ReadonlyHeaders = [...]

This will give you an array type (DataTableHeader[]). If you want the item type, you can further unwrap it:

import type { VDataTable } from 'vuetify/components'

type ReadonlyHeaders = VDataTable['$props']['headers']
type UnwrapReadonlyArray<A> = A extends Readonly<Array<infer I>> ? I : never;
type ReadonlyDataTableHeader = UnwrapReadonlyArrayType<ReadonlyHeaders>;

const headers: ReadonlyDataTableHeader[] = [...]

(the UnwrapReadonlyArray utility type unwraps the readonly array and throws away the possible undefined)

However, this turned out to need updating between Vuetify versions, while the array version did not. If possible, stick to the array version to avoid maintenance.


If you need to change the headers after declaration, you can make them mutable with another utility class:

type DeepMutable<T> = { -readonly [P in keyof T]: DeepMutable<T[P]> }
type DataTableHeader = DeepMutable<ReadonlyDataTableHeader>;

(the DeepMutable utility class maps the input type recursively to a new type, removing any readonly modifiers)

Now if you assign a DataTableHeader[] to the :headers prop TS will complain that a DeepMutable[] can't be assigned to a DeepReadonly[], but since we already know the types match, we can just tell it to shut up:

<v-data-table
  :headers="(headers as any)"

Vuetify 3.3

Up until v3.3, VDataTable was still in labs, so the component had to be imported from vuetify/labs/components. Also, Vuetify did not export a type, but only the constructor function:

import type { VDataTable } from 'vuetify/labs/components'

type Headers = InstanceType<typeof VDataTable>['headers']

(VDataTable is a constructor function, so we turn it into a type with typeof, get the type it constructs with InstanceType and then get the headers prop by index)

The array type did not include undefined, but could be an array of arrays. So unwrapping the item type was slightly different:

type UnwrapReadonlyArrayType<A> = A extends Readonly<Array<infer I>> ? UnwrapReadonlyArrayType<I> : A
type ReadonlyDataTableHeader = UnwrapReadonlyArrayType<Headers>;

(the UnwrapArrayType recursively extracts the item type from an array type until no array is left and we have the DataTableHeader)

As with 3.4, this gives you readonly types, which can be unwrapped as above.


Until Vuetify 3.3

Headers were not readonly, otherwise it is the same as above:

import { VDataTable } from 'vuetify/labs/components'

type Headers = InstanceType<typeof VDataTable>['headers'] // gives `DataTableHeader[] | DataTableHeader[][]`
// optionally unwrap DataTableHeader
type UnwrapArrayType<A> = A extends Array<infer I> ? UnwrapArrayType<I> : A
type DataTableHeader = UnwrapArrayType<Headers>
Disulfide answered 12/4, 2023 at 7:45 Comment(6)
I t worked for me. After importing the VDataTable and creating the 3 types as you suggested I just added my heaader like 'const headers: ReadonlyDataTableHeader[] = [...' and run yarn vue-tsc to check. Thanks for the tip!Breath
Does not seem to work anymore with Vuetify 3.4 :(Zigmund
Thank you @Finrod, I updated the answer for 3.4 (location of the component changed and headers prop can be undefined)Disulfide
Does not work from v3.5.5. It seems headers now nested in $props: type ReadonlyHeaders = VDataTable['$props']['headers']Excursive
Hello @MoritzRingler, indeed useful information. May I ask where did you get this source of information? I mean documentation or any other reference? If you can share please?Quinine
Hey @NehaSoni, you can explore the type of VDataTable in the IDE, the rest is Typescript. There isn't anything more specific I could point you to, I am afraid.Disulfide
S
4

Vuetify defines the DataTableHeaders type at lib/labs/components.d.ts but it is not exported for external use. You can define your own type by copying this type to use in your component.

type DataTableHeader = {
    key: string;
    value?: SelectItemKey;
    title: string;
    colspan?: number;
    rowspan?: number;
    fixed?: boolean;
    align?: 'start' | 'end';
    width?: number;
    minWidth?: string;
    maxWidth?: string;
    sortable?: boolean;
    sort?: DataTableCompareFunction;
};

const headers:DataTableHeader  = [
    { title: 'The title', key: 'the_key' },
  ]

Shaughn answered 12/4, 2023 at 2:51 Comment(0)
T
1

I'm using this to control visibility:

type ReadonlyHeaders = InstanceType<typeof VDataTable>['headers']

and headerProps + cellProps:

const hideColumn = ref<boolean>(true)

const headers = ref<ReadonlyHeaders>([
  {
    key: 'column1',
    cellProps: hideColumn.value ? { style: 'display: none' } : undefined,
    headerProps: hideColumn.value ? { style: 'display: none' } : undefined
  }
])

or you can write a helper:

const hideTableColumn = (val: boolean = true) => {
  const dn = { style: 'display:none' }
  return val
    ? {
        headerProps: dn,
        cellProps: dn
      }
    : undefined
}

and use it:

const headers = ref<ReadonlyHeaders>([
  {
    key: 'column1',
    ...hideTableColumn()
  }
])

or

...hideTableColumn(hideColumn)

but unfortenutelly it's not reactive :(

Tema answered 21/12, 2023 at 12:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.