From 164a8a5ee55eb9a80d84a19c9a48a4e3ff8dcef0 Mon Sep 17 00:00:00 2001 From: Noblet Ouways <91417411+Dsaquel@users.noreply.github.com> Date: Wed, 2 Jul 2025 05:28:11 +0200 Subject: [PATCH] refactor(components): [table] remove `@ts-nocheck` (#21200) * refactor(components): [table] remove `@ts-nocheck` * chore: remove any wip * chore: better types --- .../table/src/table-body/events-helper.ts | 34 ++++++---- .../components/table/src/table-body/index.ts | 20 +++--- .../table/src/table-body/render-helper.ts | 66 ++++++++++++------- .../table/src/table-body/styles-helper.ts | 10 +-- .../table/src/table-column/defaults.ts | 2 +- .../table/src/table-column/index.ts | 31 +++++---- .../table/src/table-column/render-helper.ts | 43 ++++++------ .../table/src/table-column/watcher-helper.ts | 18 ++--- .../table/src/table-footer/index.ts | 23 +++---- .../table/src/table-footer/mapState-helper.ts | 2 +- .../table/src/table-header/event-helper.ts | 38 +++++++---- .../table/src/table-header/index.ts | 47 +++++++------ .../table/src/table-header/utils-helper.ts | 14 ++-- .../components/table/src/table/defaults.ts | 3 +- .../table/src/table/style-helper.ts | 4 +- 15 files changed, 204 insertions(+), 151 deletions(-) diff --git a/packages/components/table/src/table-body/events-helper.ts b/packages/components/table/src/table-body/events-helper.ts index a559b5ad57..79df90d3f3 100644 --- a/packages/components/table/src/table-body/events-helper.ts +++ b/packages/components/table/src/table-body/events-helper.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { h, inject, ref } from 'vue' import { debounce } from 'lodash-unified' import { addClass, hasClass, removeClass } from '@element-plus/utils' @@ -13,24 +12,25 @@ import { TABLE_INJECTION_KEY } from '../tokens' import type { TableColumnCtx } from '../table-column/defaults' import type { TableBodyProps } from './defaults' import type { TableOverflowTooltipOptions } from '../util' +import type { DefaultRow } from '../table/defaults' function isGreaterThan(a: number, b: number, epsilon = 0.03) { return a - b > epsilon } -function useEvents(props: Partial>) { +function useEvents(props: Partial>) { const parent = inject(TABLE_INJECTION_KEY) const tooltipContent = ref('') const tooltipTrigger = ref(h('div')) const handleEvent = (event: Event, row: T, name: string) => { const table = parent const cell = getCell(event) - let column: TableColumnCtx + let column: TableColumnCtx | null = null const namespace = table?.vnode.el?.dataset.prefix if (cell) { column = getColumnByCell( { - columns: props.store.states.columns.value, + columns: props.store?.states.columns.value ?? [], }, cell, namespace @@ -45,17 +45,17 @@ function useEvents(props: Partial>) { handleEvent(event, row, 'dblclick') } const handleClick = (event: Event, row: T) => { - props.store.commit('setCurrentRow', row) + props.store?.commit('setCurrentRow', row) handleEvent(event, row, 'click') } const handleContextMenu = (event: Event, row: T) => { handleEvent(event, row, 'contextmenu') } const handleMouseEnter = debounce((index: number) => { - props.store.commit('setHoverRow', index) + props.store?.commit('setHoverRow', index) }, 30) const handleMouseLeave = debounce(() => { - props.store.commit('setHoverRow', null) + props.store?.commit('setHoverRow', null) }, 30) const getPadding = (el: HTMLElement) => { const style = window.getComputedStyle(el, null) @@ -76,11 +76,12 @@ function useEvents(props: Partial>) { event: MouseEvent, toggle: (el: Element, cls: string) => void ) => { - let node = event.target.parentNode + let node: Node | null | undefined = (event?.target as Element | null) + ?.parentNode while (rowSpan > 1) { node = node?.nextSibling if (!node || node.nodeName !== 'TR') break - toggle(node, 'hover-row hover-fixed-row') + toggle(node as Element, 'hover-row hover-fixed-row') rowSpan-- } } @@ -90,14 +91,15 @@ function useEvents(props: Partial>) { row: T, tooltipOptions: TableOverflowTooltipOptions ) => { + if (!parent) return const table = parent const cell = getCell(event) const namespace = table?.vnode.el?.dataset.prefix - let column: TableColumnCtx + let column: TableColumnCtx | null = null if (cell) { column = getColumnByCell( { - columns: props.store.states.columns.value, + columns: props.store?.states.columns.value ?? [], }, cell, namespace @@ -108,7 +110,11 @@ function useEvents(props: Partial>) { if (cell.rowSpan > 1) { toggleRowClassByCell(cell.rowSpan, event, addClass) } - const hoverState = (table.hoverState = { cell, column, row }) + const hoverState = (table.hoverState = { + cell, + column: column as any, + row, + }) table?.emit( 'cell-mouse-enter', hoverState.row, @@ -162,7 +168,7 @@ function useEvents(props: Partial>) { ) { createTablePopper( tooltipOptions, - cell.innerText || cell.textContent, + (cell?.innerText || cell?.textContent) ?? '', row, column, cell, @@ -172,7 +178,7 @@ function useEvents(props: Partial>) { removePopper?.() } } - const handleCellMouseLeave = (event) => { + const handleCellMouseLeave = (event: MouseEvent) => { const cell = getCell(event) if (!cell) return if (cell.rowSpan > 1) { diff --git a/packages/components/table/src/table-body/index.ts b/packages/components/table/src/table-body/index.ts index 609d4d85d8..1cda5bcd44 100644 --- a/packages/components/table/src/table-body/index.ts +++ b/packages/components/table/src/table-body/index.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { defineComponent, getCurrentInstance, @@ -28,8 +27,8 @@ export default defineComponent({ useRender(props) const { onColumnsChange, onScrollableChange } = useLayoutObserver(parent!) - const hoveredCellList = [] - watch(props.store.states.hoverRow, (newVal: any, oldVal: any) => { + const hoveredCellList: HTMLTableCellElement[] = [] + watch(props.store?.states.hoverRow, (newVal: any, oldVal: any) => { const el = instance?.vnode.el as HTMLElement const rows = Array.from(el?.children || []).filter((e) => e?.classList.contains(`${ns.e('row')}`) @@ -37,7 +36,8 @@ export default defineComponent({ // hover rowSpan > 1 choose the whole row let rowNum = newVal - const childNodes = rows[rowNum]?.childNodes + const childNodes = rows[rowNum] + ?.childNodes as NodeListOf if (childNodes?.length) { let control = 0 const indexes = Array.from(childNodes).reduce((acc, item, index) => { @@ -50,13 +50,15 @@ export default defineComponent({ } control > 0 && control-- return acc - }, []) + }, [] as number[]) indexes.forEach((rowIndex) => { rowNum = newVal while (rowNum > 0) { // find from previous - const preChildNodes = rows[rowNum - 1]?.childNodes + const preChildNodes = rows[rowNum - 1] + ?.childNodes as NodeListOf + if ( preChildNodes[rowIndex] && preChildNodes[rowIndex].nodeName === 'TD' && @@ -73,7 +75,7 @@ export default defineComponent({ hoveredCellList.forEach((item) => removeClass(item, 'hover-cell')) hoveredCellList.length = 0 } - if (!props.store.states.isComplex.value || !isClient) return + if (!props.store?.states.isComplex.value || !isClient) return rAF(() => { // just get first level children; fix #9723 @@ -104,7 +106,7 @@ export default defineComponent({ }, render() { const { wrappedRowRender, store } = this - const data = store.states.data.value || [] + const data = store?.states.data.value || [] // Why do we need tabIndex: -1 ? // If you set the tabindex attribute on an element , // then its child content cannot be scrolled with the arrow keys, @@ -112,7 +114,7 @@ export default defineComponent({ // See https://github.com/facebook/react/issues/25462#issuecomment-1274775248 or https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes/tabindex return h('tbody', { tabIndex: -1 }, [ data.reduce((acc: VNode[], row) => { - return acc.concat(wrappedRowRender(row, acc.length)) + return acc.concat(wrappedRowRender(row, acc.length) as VNode[]) }, []), ]) }, diff --git a/packages/components/table/src/table-body/render-helper.ts b/packages/components/table/src/table-body/render-helper.ts index 879ffa842d..5630666975 100644 --- a/packages/components/table/src/table-body/render-helper.ts +++ b/packages/components/table/src/table-body/render-helper.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { computed, h, inject } from 'vue' import { merge } from 'lodash-unified' import { useNamespace } from '@element-plus/hooks' @@ -10,10 +9,19 @@ import useStyles from './styles-helper' import TdWrapper from './td-wrapper.vue' import type { TableBodyProps } from './defaults' -import type { RenderRowData, TableProps, TreeNode } from '../table/defaults' +import type { + DefaultRow, + RenderRowData, + Table, + TableColumnCtx, + TableProps, + TreeNode, +} from '../table/defaults' +import type { TreeData } from '../store/tree' +import type { TableOverflowTooltipOptions } from '../util' -function useRender(props: Partial>) { - const parent = inject(TABLE_INJECTION_KEY) +function useRender(props: Partial>) { + const parent = inject(TABLE_INJECTION_KEY) as Table const ns = useNamespace('table') const { handleDoubleClick, @@ -35,12 +43,12 @@ function useRender(props: Partial>) { getColspanRealWidth, } = useStyles(props) const firstDefaultColumnIndex = computed(() => { - return props.store.states.columns.value.findIndex( + return props.store?.states.columns.value.findIndex( ({ type }) => type === 'default' ) }) const getKeyOfRow = (row: T, index: number) => { - const rowKey = (parent.props as Partial>).rowKey + const rowKey = (parent?.props as Partial>)?.rowKey if (rowKey) { return getRowIdentity(row, rowKey) } @@ -53,12 +61,12 @@ function useRender(props: Partial>) { expanded = false ) => { const { tooltipEffect, tooltipOptions, store } = props - const { indent, columns } = store.states + const { indent, columns } = store!.states const rowClasses = getRowClass(row, $index) let display = true if (treeRowData) { rowClasses.push(ns.em('row', `level-${treeRowData.level}`)) - display = treeRowData.display + display = !!treeRowData.display } const displayStyle = display ? null : { display: 'none' } return h( @@ -67,9 +75,9 @@ function useRender(props: Partial>) { style: [displayStyle, getRowStyle(row, $index)], class: rowClasses, key: getKeyOfRow(row, $index), - onDblclick: ($event) => handleDoubleClick($event, row), - onClick: ($event) => handleClick($event, row), - onContextmenu: ($event) => handleContextMenu($event, row), + onDblclick: ($event: Event) => handleDoubleClick($event, row), + onClick: ($event: Event) => handleClick($event, row), + onContextmenu: ($event: Event) => handleContextMenu($event, row), onMouseenter: () => handleMouseEnter($index), onMouseleave: handleMouseLeave, }, @@ -85,8 +93,8 @@ function useRender(props: Partial>) { cellIndex ) const data: RenderRowData = { - store: props.store, - _self: props.context || parent, + store: store!, + _self: props.context || parent!, column: columnData, row, $index, @@ -95,7 +103,7 @@ function useRender(props: Partial>) { } if (cellIndex === firstDefaultColumnIndex.value && treeRowData) { data.treeNode = { - indent: treeRowData.level * indent.value, + indent: treeRowData.level && treeRowData.level * indent.value, level: treeRowData.level, } if (isBoolean(treeRowData.expanded)) { @@ -128,8 +136,12 @@ function useRender(props: Partial>) { key: `${patchKey}${baseKey}`, rowspan, colspan, - onMouseenter: ($event) => - handleCellMouseEnter($event, row, mergedTooltipOptions), + onMouseenter: ($event: MouseEvent) => + handleCellMouseEnter( + $event, + row, + mergedTooltipOptions as TableOverflowTooltipOptions + ), onMouseleave: handleCellMouseLeave, }, { @@ -139,12 +151,16 @@ function useRender(props: Partial>) { }) ) } - const cellChildren = (cellIndex, column, data) => { + const cellChildren = ( + _cellIndex: number, + column: TableColumnCtx, + data: RenderRowData + ) => { return column.renderCell(data) } const wrappedRowRender = (row: T, $index: number) => { - const store = props.store + const store = props.store! const { isRowExpanded, assertRowKey } = store const { treeData, lazyTreeNodeMap, childrenColumnName, rowKey } = store.states @@ -153,7 +169,7 @@ function useRender(props: Partial>) { if (hasExpandColumn) { const expanded = isRowExpanded(row) const tr = rowRender(row, $index, undefined, expanded) - const renderExpanded = parent.renderExpanded + const renderExpanded = parent?.renderExpanded if (!renderExpanded) { console.error('[Element Error]renderExpanded is required.') return tr @@ -200,26 +216,28 @@ function useRender(props: Partial>) { expanded: cur.expanded, level: cur.level, display: true, + noLazyChildren: undefined as boolean | undefined, + loading: undefined as boolean | undefined, } if (isBoolean(cur.lazy)) { - if (isBoolean(cur.loaded) && cur.loaded) { + if (treeRowData && isBoolean(cur.loaded) && cur.loaded) { treeRowData.noLazyChildren = !(cur.children && cur.children.length) } treeRowData.loading = cur.loading } } - const tmp = [rowRender(row, $index, treeRowData)] + const tmp = [rowRender(row, $index, treeRowData ?? undefined)] // 渲染嵌套数据 if (cur) { // currentRow 记录的是 index,所以还需主动增加 TreeTable 的 index let i = 0 - const traverse = (children, parent) => { + const traverse = (children: T[], parent: TreeData) => { if (!(children && children.length && parent)) return children.forEach((node) => { // 父节点的 display 状态影响子节点的显示状态 - const innerTreeRowData = { + const innerTreeRowData: Partial> = { display: parent.display && parent.expanded, - level: parent.level + 1, + level: parent.level! + 1, expanded: false, noLazyChildren: false, loading: false, diff --git a/packages/components/table/src/table-body/styles-helper.ts b/packages/components/table/src/table-body/styles-helper.ts index e532f3ad15..4aa5a33aed 100644 --- a/packages/components/table/src/table-body/styles-helper.ts +++ b/packages/components/table/src/table-body/styles-helper.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { inject } from 'vue' import { useNamespace } from '@element-plus/hooks' import { isArray, isFunction, isObject, isString } from '@element-plus/utils' @@ -11,9 +10,10 @@ import { TABLE_INJECTION_KEY } from '../tokens' import type { TableColumnCtx } from '../table-column/defaults' import type { TableBodyProps } from './defaults' +import type { DefaultRow, Table } from '../table/defaults' -function useStyles(props: Partial>) { - const parent = inject(TABLE_INJECTION_KEY) +function useStyles(props: Partial>) { + const parent = inject(TABLE_INJECTION_KEY) as Table const ns = useNamespace('table') const getRowStyle = (row: T, rowIndex: number) => { @@ -31,7 +31,7 @@ function useStyles(props: Partial>) { const classes = [ns.e('row')] if ( parent?.props.highlightCurrentRow && - row === props.store.states.currentRow.value + row === props.store?.states.currentRow.value ) { classes.push('current-row') } @@ -143,7 +143,7 @@ function useStyles(props: Partial>) { index: number ): number => { if (colspan < 1) { - return columns[index].realWidth + return columns[index].realWidth! } const widthArr = columns .map(({ realWidth, width }) => realWidth || width) diff --git a/packages/components/table/src/table-column/defaults.ts b/packages/components/table/src/table-column/defaults.ts index b954c2b9ea..27afdba3f7 100644 --- a/packages/components/table/src/table-column/defaults.ts +++ b/packages/components/table/src/table-column/defaults.ts @@ -65,7 +65,7 @@ type TableColumnCtx = { filterClassName: string index: number | ((index: number) => number) sortOrders: (TableSortOrder | null)[] - renderCell: (data: any) => void + renderCell: (data: any) => VNode | VNode[] colSpan: number rowSpan: number children?: TableColumnCtx[] diff --git a/packages/components/table/src/table-column/index.ts b/packages/components/table/src/table-column/index.ts index 294b4e2708..fbcd70ab46 100644 --- a/packages/components/table/src/table-column/index.ts +++ b/packages/components/table/src/table-column/index.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Fragment, computed, @@ -18,11 +17,13 @@ import useWatcher from './watcher-helper' import useRender from './render-helper' import defaultProps from './defaults' +import type { VNode } from 'vue' import type { TableColumn, TableColumnCtx } from './defaults' import type { DefaultRow } from '../table/defaults' let columnIdSeed = 1 +//TODO: when vue 3.3 we can set this component a generic: https://github.com/vuejs/core/pull/7963 export default defineComponent({ name: 'ElTableColumn', components: { @@ -56,16 +57,17 @@ export default defineComponent({ getColumnElIndex, realAlign, updateColumnOrder, - } = useRender(props as unknown as TableColumnCtx, slots, owner) + } = useRender(props as unknown as TableColumnCtx, slots, owner) const parent = columnOrTableParent.value columnId.value = `${ - parent.tableId || parent.columnId + ('tableId' in parent && parent.tableId) || + ('columnId' in parent && parent.columnId) }_column_${columnIdSeed++}` onBeforeMount(() => { isSubColumn.value = owner.value !== parent - const type = props.type || 'default' + const type = (props.type as keyof typeof cellStarts) || 'default' const sortable = props.sortable === '' ? true : props.sortable //The selection column should not be affected by `showOverflowTooltip`. const showOverflowTooltip = @@ -134,7 +136,7 @@ export default defineComponent({ setColumnWidth, setColumnForcedProps ) - column = chains(column) + column = chains(column) as unknown as TableColumnCtx columnConfig.value = column // 注册 watcher @@ -144,7 +146,7 @@ export default defineComponent({ onMounted(() => { const parent = columnOrTableParent.value const children = isSubColumn.value - ? parent.vnode.el.children + ? parent.vnode.el?.children : parent.refs.hiddenColumns?.children const getColumnIndex = () => getColumnElIndex(children || [], instance.vnode.el) @@ -154,7 +156,9 @@ export default defineComponent({ owner.value.store.commit( 'insertColumn', columnConfig.value, - isSubColumn.value ? parent.columnConfig.value : null, + isSubColumn.value + ? 'columnConfig' in parent && parent.columnConfig.value + : null, updateColumnOrder ) }) @@ -165,13 +169,15 @@ export default defineComponent({ owner.value.store.commit( 'removeColumn', columnConfig.value, - isSubColumn.value ? parent.columnConfig.value : null, + isSubColumn.value + ? 'columnConfig' in parent && parent.columnConfig.value + : null, updateColumnOrder ) }) instance.columnId = columnId.value - instance.columnConfig = columnConfig + instance.columnConfig = columnConfig as any return }, render() { @@ -185,7 +191,7 @@ export default defineComponent({ if (isArray(renderDefault)) { for (const childNode of renderDefault) { if ( - childNode.type?.name === 'ElTableColumn' || + (childNode.type as any)?.name === 'ElTableColumn' || childNode.shapeFlag & 2 ) { children.push(childNode) @@ -195,7 +201,10 @@ export default defineComponent({ ) { childNode.children.forEach((vnode) => { // No rendering when vnode is dynamic slot or text - if (vnode?.patchFlag !== 1024 && !isString(vnode?.children)) { + if ( + (vnode as VNode)?.patchFlag !== 1024 && + !isString((vnode as VNode)?.children) + ) { children.push(vnode) } }) diff --git a/packages/components/table/src/table-column/render-helper.ts b/packages/components/table/src/table-column/render-helper.ts index 831fa63bfd..cdb942553d 100644 --- a/packages/components/table/src/table-column/render-helper.ts +++ b/packages/components/table/src/table-column/render-helper.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Comment, computed, @@ -19,19 +18,20 @@ import { } from '../config' import { parseMinWidth, parseWidth } from '../util' -import type { ComputedRef } from 'vue' +import type { ComputedRef, RendererNode, Slots, VNode } from 'vue' import type { TableColumn, TableColumnCtx } from './defaults' +import type { DefaultRow, Table } from '../table/defaults' -function useRender( +function useRender( props: TableColumnCtx, - slots, - owner: ComputedRef + slots: Slots, + owner: ComputedRef> ) { const instance = getCurrentInstance() as TableColumn const columnId = ref('') const isSubColumn = ref(false) - const realAlign = ref() - const realHeaderAlign = ref() + const realAlign = ref() + const realHeaderAlign = ref() const ns = useNamespace('table') watchEffect(() => { realAlign.value = props.align ? `is-${props.align}` : null @@ -45,7 +45,7 @@ function useRender( // nextline help render realHeaderAlign.value }) - const columnOrTableParent = computed(() => { + const columnOrTableParent = computed | TableColumn>(() => { let parent: any = instance.vnode.vParent || instance.parent while (parent && !parent.tableId && !parent.columnId) { parent = parent.vnode.vParent || parent.parent @@ -53,7 +53,7 @@ function useRender( return parent }) const hasTreeColumn = computed(() => { - const { store } = instance.parent + const { store } = (instance.parent as Table)! if (!store) return false const { treeData } = store.states const treeDataValue = treeData.value @@ -81,11 +81,11 @@ function useRender( const setColumnForcedProps = (column: TableColumnCtx) => { // 对于特定类型的 column,某些属性不允许设置 const type = column.type - const source = cellForced[type] || {} + const source = cellForced[type as keyof typeof cellForced] || {} Object.keys(source).forEach((prop) => { - const value = source[prop] + const value = source[prop as keyof typeof source] if (prop !== 'className' && !isUndefined(value)) { - column[prop] = value + ;(column as any)[prop] = value } }) const className = getDefaultClassName(type) @@ -98,13 +98,13 @@ function useRender( return column } - const checkSubColumn = (children: TableColumn | TableColumn[]) => { + const checkSubColumn = (children: VNode | VNode[]) => { if (isArray(children)) { children.forEach((child) => check(child)) } else { check(children) } - function check(item: TableColumn) { + function check(item: any) { if (item?.type?.name === 'ElTableColumn') { item.vParent = instance } @@ -112,6 +112,7 @@ function useRender( } const setColumnRenders = (column: TableColumnCtx) => { // renderHeader 属性不推荐使用。 + //@ts-expect-error if (props.renderHeader) { debugWarn( 'TableColumn', @@ -149,14 +150,14 @@ function useRender( }, [originRenderCell(data)] ) - owner.value.renderExpanded = (data) => { - return slots.default ? slots.default(data) : slots.default + owner.value.renderExpanded = (row) => { + return slots.default ? slots.default(row) : slots.default } } else { originRenderCell = originRenderCell || defaultRenderCell // 对 renderCell 进行包装 column.renderCell = (data) => { - let children = null + let children: VNode | VNode[] | null = null if (slots.default) { const vnodes = slots.default(data) children = vnodes.some((v) => v.type !== Comment) @@ -191,17 +192,17 @@ function useRender( } return column } - const getPropsData = (...propsKey: unknown[]) => { + const getPropsData = (...propsKey: string[][]) => { return propsKey.reduce((prev, cur) => { if (isArray(cur)) { cur.forEach((key) => { - prev[key] = props[key] + prev[key] = props[key as keyof TableColumnCtx] }) } return prev - }, {}) + }, {} as Record) } - const getColumnElIndex = (children, child) => { + const getColumnElIndex = (children: T[], child: RendererNode | null) => { return Array.prototype.indexOf.call(children, child) } diff --git a/packages/components/table/src/table-column/watcher-helper.ts b/packages/components/table/src/table-column/watcher-helper.ts index 5e7f178f25..27b44cb601 100644 --- a/packages/components/table/src/table-column/watcher-helper.ts +++ b/packages/components/table/src/table-column/watcher-helper.ts @@ -1,25 +1,25 @@ -// @ts-nocheck import { getCurrentInstance, watch } from 'vue' import { hasOwn } from '@element-plus/utils' import { parseMinWidth, parseWidth } from '../util' import type { ComputedRef } from 'vue' +import type { DefaultRow } from '../table/defaults' import type { TableColumn, TableColumnCtx, ValueOf } from './defaults' -function getAllAliases(props, aliases) { +function getAllAliases(props: string[], aliases: Record) { return props.reduce((prev, cur) => { - prev[cur] = cur + prev[cur as keyof typeof prev] = cur return prev }, aliases) } -function useWatcher( +function useWatcher( owner: ComputedRef, props_: Partial> ) { const instance = getCurrentInstance() as TableColumn const registerComplexWatchers = () => { const props = ['fixed'] - const aliases = { + const aliases: Record = { realWidth: 'width', realMinWidth: 'minWidth', } @@ -37,8 +37,8 @@ function useWatcher( if (columnKey === 'minWidth' && key === 'realMinWidth') { value = parseMinWidth(newVal) } - instance.columnConfig.value[columnKey as any] = value - instance.columnConfig.value[key] = value + instance.columnConfig.value[columnKey as never] = value as never + instance.columnConfig.value[key as never] = value as never const updateColumns = columnKey === 'fixed' owner.value.store.scheduleLayout(updateColumns) } @@ -61,7 +61,7 @@ function useWatcher( 'showOverflowTooltip', 'tooltipFormatter', ] - const aliases = { + const aliases: Record = { property: 'prop', align: 'realAlign', headerAlign: 'realHeaderAlign', @@ -73,7 +73,7 @@ function useWatcher( watch( () => props_[columnKey], (newVal) => { - instance.columnConfig.value[key] = newVal + instance.columnConfig.value[key as never] = newVal } ) } diff --git a/packages/components/table/src/table-footer/index.ts b/packages/components/table/src/table-footer/index.ts index 4da250d475..8e214bf438 100644 --- a/packages/components/table/src/table-footer/index.ts +++ b/packages/components/table/src/table-footer/index.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { defineComponent, h, inject } from 'vue' import { useNamespace } from '@element-plus/hooks' import useLayoutObserver from '../layout-observer' @@ -6,10 +5,10 @@ import { TABLE_INJECTION_KEY } from '../tokens' import useStyle from './style-helper' import type { Store } from '../store' -import type { PropType } from 'vue' -import type { DefaultRow, Sort, SummaryMethod } from '../table/defaults' +import type { PropType, VNode } from 'vue' +import type { DefaultRow, Sort, SummaryMethod, Table } from '../table/defaults' -export interface TableFooter { +export interface TableFooter { fixed: string store: Store summaryMethod: SummaryMethod @@ -28,15 +27,13 @@ export default defineComponent({ }, store: { required: true, - type: Object as PropType['store']>, + type: Object as PropType['store']>, }, - summaryMethod: Function as PropType< - TableFooter['summaryMethod'] - >, + summaryMethod: Function as PropType['summaryMethod']>, sumText: String, border: Boolean, defaultSort: { - type: Object as PropType['defaultSort']>, + type: Object as PropType['defaultSort']>, default: () => { return { prop: '', @@ -46,10 +43,10 @@ export default defineComponent({ }, }, setup(props) { - const parent = inject(TABLE_INJECTION_KEY) + const parent = inject(TABLE_INJECTION_KEY) as Table const ns = useNamespace('table') const { getCellClasses, getCellStyles, columns } = useStyle( - props as TableFooter + props as TableFooter ) const { onScrollableChange, onColumnsChange } = useLayoutObserver(parent!) @@ -66,7 +63,7 @@ export default defineComponent({ const { columns, getCellStyles, getCellClasses, summaryMethod, sumText } = this const data = this.store.states.data.value - let sums = [] + let sums: (string | VNode | number | undefined)[] = [] if (summaryMethod) { sums = summaryMethod({ columns, @@ -79,7 +76,7 @@ export default defineComponent({ return } const values = data.map((item) => Number(item[column.property])) - const precisions = [] + const precisions: number[] = [] let notNumber = true values.forEach((value) => { if (!Number.isNaN(+value)) { diff --git a/packages/components/table/src/table-footer/mapState-helper.ts b/packages/components/table/src/table-footer/mapState-helper.ts index e214005063..fddf1af241 100644 --- a/packages/components/table/src/table-footer/mapState-helper.ts +++ b/packages/components/table/src/table-footer/mapState-helper.ts @@ -26,7 +26,7 @@ function useMapState() { columnsCount, leftFixedCount, rightFixedCount, - columns: store?.states.columns ?? [], + columns: computed(() => store?.states.columns.value ?? []), } } diff --git a/packages/components/table/src/table-header/event-helper.ts b/packages/components/table/src/table-header/event-helper.ts index 629e8ad2c5..fb6798ca7f 100644 --- a/packages/components/table/src/table-header/event-helper.ts +++ b/packages/components/table/src/table-header/event-helper.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { getCurrentInstance, inject, ref } from 'vue' import { isNull } from 'lodash-unified' import { @@ -10,10 +9,15 @@ import { } from '@element-plus/utils' import { TABLE_INJECTION_KEY } from '../tokens' +import type { EmitFn } from '@element-plus/utils' import type { TableHeaderProps } from '.' import type { TableColumnCtx } from '../table-column/defaults' +import type { DefaultRow, TableSortOrder } from '../table/defaults' -function useEvent(props: TableHeaderProps, emit) { +function useEvent( + props: TableHeaderProps, + emit: EmitFn +) { const instance = getCurrentInstance() const parent = inject(TABLE_INJECTION_KEY) const handleFilterClick = (event: Event) => { @@ -33,9 +37,14 @@ function useEvent(props: TableHeaderProps, emit) { const handleHeaderContextMenu = (event: Event, column: TableColumnCtx) => { parent?.emit('header-contextmenu', column, event) } - const draggingColumn = ref(null) + const draggingColumn = ref | null>(null) const dragging = ref(false) - const dragState = ref({}) + const dragState = ref<{ + startMouseLeft: number + startLeft: number + startColumnLeft: number + tableLeft: number + }>() const handleMouseDown = (event: MouseEvent, column: TableColumnCtx) => { if (!isClient) return if (column.children && column.children.length > 0) return @@ -46,8 +55,8 @@ function useEvent(props: TableHeaderProps, emit) { const table = parent emit('set-drag-visible', true) const tableEl = table?.vnode.el - const tableLeft = tableEl.getBoundingClientRect().left - const columnEl = instance.vnode.el.querySelector(`th.${column.id}`) + const tableLeft = tableEl?.getBoundingClientRect().left + const columnEl = instance?.vnode?.el?.querySelector(`th.${column.id}`) const columnRect = columnEl.getBoundingClientRect() const minLeft = columnRect.left - tableLeft + 30 @@ -96,7 +105,7 @@ function useEvent(props: TableHeaderProps, emit) { document.body.style.cursor = '' dragging.value = false draggingColumn.value = null - dragState.value = {} + dragState.value = undefined emit('set-drag-visible', false) } @@ -136,7 +145,7 @@ function useEvent(props: TableHeaderProps, emit) { if (hasClass(target, 'is-sortable')) { target.style.cursor = 'col-resize' } - draggingColumn.value = column + draggingColumn.value = column as any } else if (!dragging.value) { bodyStyle.cursor = '' if (hasClass(target, 'is-sortable')) { @@ -151,19 +160,20 @@ function useEvent(props: TableHeaderProps, emit) { if (!isClient) return document.body.style.cursor = '' } - const toggleOrder = ({ order, sortOrders }) => { - if (order === '') return sortOrders[0] + const toggleOrder = ({ order, sortOrders }: TableColumnCtx) => { + if ((order as string) === '') return sortOrders[0] const index = sortOrders.indexOf(order || null) return sortOrders[index > sortOrders.length - 2 ? 0 : index + 1] } const handleSortClick = ( event: Event, column: TableColumnCtx, - givenOrder: string | boolean + givenOrder?: TableSortOrder | boolean ) => { event.stopPropagation() - const order = + const order = ( column.order === givenOrder ? null : givenOrder || toggleOrder(column) + ) as TableSortOrder | null const target = (event.target as HTMLElement)?.closest('th') if (target) { @@ -179,7 +189,9 @@ function useEvent(props: TableHeaderProps, emit) { if ( ['ascending', 'descending'].some( - (str) => hasClass(clickTarget, str) && !column.sortOrders.includes(str) + (str) => + hasClass(clickTarget as Element, str) && + !column.sortOrders.includes(str as TableSortOrder) ) ) { return diff --git a/packages/components/table/src/table-header/index.ts b/packages/components/table/src/table-header/index.ts index 0784b0809b..696b73f6c3 100644 --- a/packages/components/table/src/table-header/index.ts +++ b/packages/components/table/src/table-header/index.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { defineComponent, getCurrentInstance, @@ -15,6 +14,7 @@ import { useNamespace } from '@element-plus/hooks' import FilterPanel from '../filter-panel.vue' import useLayoutObserver from '../layout-observer' import { TABLE_INJECTION_KEY } from '../tokens' +import TableLayout from '../table-layout' import useEvent from './event-helper' import useStyle from './style.helper' import useUtils from './utils-helper' @@ -25,12 +25,12 @@ import type { Store } from '../store' export interface TableHeader extends ComponentInternalInstance { state: { - onColumnsChange - onScrollableChange + onColumnsChange: (layout: TableLayout) => void + onScrollableChange: (layout: TableLayout) => void } filterPanels: Ref } -export interface TableHeaderProps { +export interface TableHeaderProps { fixed: string store: Store border: boolean @@ -50,11 +50,11 @@ export default defineComponent({ }, store: { required: true, - type: Object as PropType['store']>, + type: Object as PropType['store']>, }, border: Boolean, defaultSort: { - type: Object as PropType['defaultSort']>, + type: Object as PropType['defaultSort']>, default: () => { return { prop: '', @@ -117,15 +117,15 @@ export default defineComponent({ handleMouseOut, handleSortClick, handleFilterClick, - } = useEvent(props as TableHeaderProps, emit) + } = useEvent(props as TableHeaderProps, emit) const { getHeaderRowStyle, getHeaderRowClass, getHeaderCellStyle, getHeaderCellClass, - } = useStyle(props as TableHeaderProps) + } = useStyle(props as TableHeaderProps) const { isGroup, toggleAllSelection, columnRows } = useUtils( - props as TableHeaderProps + props as TableHeaderProps ) instance.state = { @@ -220,16 +220,22 @@ export default defineComponent({ subColumns, column ), - onClick: ($event) => { - if ($event.currentTarget.classList.contains('noclick')) { + onClick: ($event: Event) => { + if ( + ($event.currentTarget as Element)?.classList.contains( + 'noclick' + ) + ) { return } handleHeaderClick($event, column) }, - onContextmenu: ($event) => + onContextmenu: ($event: MouseEvent) => handleHeaderContextMenu($event, column), - onMousedown: ($event) => handleMouseDown($event, column), - onMousemove: ($event) => handleMouseMove($event, column), + onMousedown: ($event: MouseEvent) => + handleMouseDown($event, column), + onMousemove: ($event: MouseEvent) => + handleMouseMove($event, column), onMouseout: handleMouseOut, }, [ @@ -256,17 +262,18 @@ export default defineComponent({ h( 'span', { - onClick: ($event) => handleSortClick($event, column), + onClick: ($event: Event) => + handleSortClick($event, column), class: 'caret-wrapper', }, [ h('i', { - onClick: ($event) => + onClick: ($event: Event) => handleSortClick($event, column, 'ascending'), class: 'sort-caret ascending', }), h('i', { - onClick: ($event) => + onClick: ($event: Event) => handleSortClick($event, column, 'descending'), class: 'sort-caret descending', }), @@ -274,13 +281,13 @@ export default defineComponent({ ), column.filterable && h( - FilterPanel, + FilterPanel as any, { store, placement: column.filterPlacement || 'bottom-start', - appendTo: $parent.appendFilterPanelTo, + appendTo: ($parent as any)?.appendFilterPanelTo, column, - upDataColumn: (key, value) => { + upDataColumn: (key: never, value: never) => { column[key] = value }, }, diff --git a/packages/components/table/src/table-header/utils-helper.ts b/packages/components/table/src/table-header/utils-helper.ts index 72c2cd86c5..e198f4e922 100644 --- a/packages/components/table/src/table-header/utils-helper.ts +++ b/packages/components/table/src/table-header/utils-helper.ts @@ -1,11 +1,11 @@ -// @ts-nocheck import { computed, inject } from 'vue' import { TABLE_INJECTION_KEY } from '../tokens' +import type { DefaultRow } from '../table/defaults' import type { TableColumnCtx } from '../table-column/defaults' import type { TableHeaderProps } from '.' -const getAllColumns = ( +const getAllColumns = ( columns: TableColumnCtx[] ): TableColumnCtx[] => { const result: TableColumnCtx[] = [] @@ -21,11 +21,11 @@ const getAllColumns = ( return result } -export const convertToRows = ( +export const convertToRows = ( originColumns: TableColumnCtx[] -): TableColumnCtx[] => { +): TableColumnCtx[][] => { let maxLevel = 1 - const traverse = (column: TableColumnCtx, parent: TableColumnCtx) => { + const traverse = (column: TableColumnCtx, parent?: TableColumnCtx) => { if (parent) { column.level = parent.level + 1 if (maxLevel < column.level) { @@ -49,7 +49,7 @@ export const convertToRows = ( traverse(column, undefined) }) - const rows = [] + const rows: TableColumnCtx[][] = [] for (let i = 0; i < maxLevel; i++) { rows.push([]) } @@ -69,7 +69,7 @@ export const convertToRows = ( return rows } -function useUtils(props: TableHeaderProps) { +function useUtils(props: TableHeaderProps) { const parent = inject(TABLE_INJECTION_KEY) const columnRows = computed(() => { return convertToRows(props.store.states.originColumns.value) diff --git a/packages/components/table/src/table/defaults.ts b/packages/components/table/src/table/defaults.ts index aff7365297..2e7271fcee 100644 --- a/packages/components/table/src/table/defaults.ts +++ b/packages/components/table/src/table/defaults.ts @@ -64,7 +64,7 @@ type RenderExpanded = ({ $index, store, expanded, -}: RIS) => VNode +}: RIS) => VNode[] | undefined type SummaryMethod = (data: { columns: TableColumnCtx[] @@ -443,4 +443,5 @@ export type { TreeProps, TableTooltipData, TableSortOrder, + RenderExpanded, } diff --git a/packages/components/table/src/table/style-helper.ts b/packages/components/table/src/table/style-helper.ts index 823380c25c..bb5a6dffc8 100644 --- a/packages/components/table/src/table/style-helper.ts +++ b/packages/components/table/src/table/style-helper.ts @@ -10,7 +10,7 @@ import { import { useEventListener, useResizeObserver } from '@vueuse/core' import { useFormSize } from '@element-plus/components/form' -import type { DefaultRow, Table, TableProps } from './defaults' +import type { DefaultRow, RenderExpanded, Table, TableProps } from './defaults' import type { Store } from '../store' import type TableLayout from '../table-layout' import type { TableColumnCtx } from '../table-column/defaults' @@ -22,7 +22,7 @@ function useStyle( table: Table ) { const isHidden = ref(false) - const renderExpanded = ref(null) + const renderExpanded = ref | null>(null) const resizeProxyVisible = ref(false) const setDragVisible = (visible: boolean) => { resizeProxyVisible.value = visible