ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Handsontable TypeScript 类型系统完全指南:声明入口、类型参考与实战类型安全

Handsontable TypeScript 类型系统完全指南:声明入口、类型参考与实战类型安全 前端UI组件【免费下载链接】handsontableJavaScript Data Grid / Data Table with a Spreadsheet Look Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡项目地址https://gitcode.com/gh_mirrors/ha/handsontable点击查看免费下载Handsontable 为整个公共 API 提供了开箱即用的 TypeScript 声明文件.d.ts本文是官方类型参考文档的完整展开版涵盖支持的最低 TypeScript 版本与声明降级机制、handsontable与handsontable/base两个类型入口的选择、从配置类型到主题类型/Overlay 类型的全量类型清单以及 settings 对象、hook 回调、自定义 renderer/editor、React/Angular/Vue 实例引用的实战写法。读完本文你将能在自己的 Handsontable 项目中获得完整的类型检查与 IDE 自动补全并理解这些声明在仓库中是如何生成与维护的。支持的 TypeScript 版本官方发布的.d.ts文件要求TypeScript 5.1 或更高版本。如果项目使用低于 5.1 的 TypeScript请先升级 TypeScript 版本再使用这些声明。Handsontable 内部使用最新的 TypeScript 版本进行开发与编译当前仓库的 handsontable/package.json 中开发依赖为typescript: ^6.0.0以获得最严格的内部类型检查和最新的语言特性。但发布出去的声明文件会被降级downlevel到 TS 5.1 兼容级别构建时脚本会把只存在于 TS 5.2 的类型WeakKey、Disposable、AsyncDisposable替换为 TS 5.1 等价物把只存在于 TS 5.6 的类型ArrayIterator、IteratorObject等替换为对应的迭代器类型。这一降级过程由 handsontable/scripts/downlevel-dts.mjs 实现其注释明确写着The published .d.ts must be consumable by TypeScript 5.1. The dev compiler may be a newer TS version — only the output is downleveled.发布的 .d.ts 必须能被 TS 5.1 消费开发编译器可以更新只有输出被降级。脚本的具体替换规则包括源类型较新 TS替换为TS 5.1 兼容所属版本ArrayIterator/MapIterator/SetIterator/StringIteratorIterableIteratorTS 5.6BuiltinIteratorReturnanyTS 5.6IteratorObject...IterableIteratorT1保留第一个类型参数见GENERIC_REPLACEMENTSTS 5.6AsyncIteratorObject...AsyncIterableIteratorT1TS 5.6WeakKeyobjectTS 5.2Disposable/AsyncDisposableobjectTS 5.2注意IteratorObject这类泛型不能简单用正则替换——其第一个类型参数本身可能包含嵌套尖括号如IteratorObjectMapK, V, undefined所以 downlevel-dts.mjs 用括号深度计数bracket depth counting来定位第一个类型参数的边界再折叠多余参数。另外需要了解在未来的主版本中提高最低支持的 TypeScript 版本对使用者而言属于破坏性变更breaking change任何此类变更都会在该版本的迁移指南中明确说明。因此在升级 Handsontable 主版本前务必留意迁移指南中的版本要求说明。类型入口两个入口点Handsontable 从两个入口点暴露类型两者提供完全相同的类型选择哪个取决于你如何导入库本身完整包Full package——所有模块已预先注册不做 tree shakingimport Handsontable, { GridSettings, HotInstance } from handsontable;基础包Base package——当你只导入需要的模块时使用import Handsontable, { GridSettings, HotInstance } from handsontable/base;这些入口的类型映射在 handsontable/package.json 的exports字段中有明确声明.根入口的import条件指向./index.d.mts、require条件指向./index.d.ts./base入口同理指向./base.d.mts/./base.d.ts。也就是说无论是 ESM 还是 CommonJS 消费者都能拿到对应的类型声明。对于下面列出的所有类型也都可以使用 TypeScript 的import type语法它不会产生任何运行时输出import type { GridSettings, HotInstance } from handsontable;此外仓库还单独导出了handsontable/settings子路径见 handsontable/package.json核心设置类型如RowObject、CellValue、CellChange、ChangeSource、ColumnSettings、CellMeta、CellProperties等都从这里对外再导出外部消费者可以直接import ... from handsontable/settings对应源码 handsontable/src/settings.ts 的注释说明。类型参考Type reference配置类型Configuration types这些类型描述传入new Handsontable()或updateSettings()的设置对象类型说明GridSettings所有 Handsontable 配置项。用于顶层设置对象。ColumnSettings列级覆盖。columns数组中的每一项使用该类型。CellProperties全局 → 列 → 单元格级联合并后的单元格级设置。渲染时只读。CellMeta可变mutable的单元格级元数据存储在hot.getCellMeta()中。继承CellProperties。Events所有 hook 回调签名以 hook 名为键。用于为单个 hook 函数标注类型。SanitizerContext网格传给sanitizer选项的写入面write surface。用它标注选项的第二个参数可获得这些值的补全。TextExtractorContext网格传给textExtractor选项的消费面。用它标注选项的第二个参数可获得这些值的补全。import type { GridSettings, ColumnSettings } from handsontable; const columns: ColumnSettings[] [ { data: name, type: text }, { data: revenue, type: numeric, numericFormat: { style: currency, currency: USD, minimumFractionDigits: 2, maximumFractionDigits: 2 } }, ]; const settings: GridSettings { data: myData, columns, licenseKey: non-commercial-and-evaluation, };从源码结构看GridSettings定义在 handsontable/src/core/settings.ts它带有一个宽泛的索引签名[key: string]: any以便允许任意插件/元数据键。正因如此handsontable/src/settings.ts 中定义ColumnSettings时使用了OmitRemoveIndexSignatureGridSettings, data先用RemoveIndexSignature剥掉索引签名再执行Omit否则Omit会把所有命名选项塌缩成裸索引签名所有读取都变成any自动补全消失。ColumnSettings重新声明了data?: string | number | ColumnDataGetterSetterFunction使其语义更贴合每列一个 data。CellMeta在 handsontable/src/settings.ts 中扩展了ColumnSettings额外加入className、readOnly、valid、comment、isSearchResult、hidden、skipRowOnPaste等单元格级属性CellProperties同文件 L112-L119再叠加渲染期计算出的row、col、instance、visualRow、visualCol、prop字段。SanitizerContext在 handsontable/src/core/settings.ts 中定义为字符串联合header | password | contextMenu | selectEditor | dialog | notification | CopyPaste.paste | CopyPaste.paste.sourceData | (string {})。(string {})这一成员是为了兼容调用方自定义 sanitizer、与其他库共用 sanitizer 或未来新增写入面的场景——代价是类型无法拒绝拼写错误的值。数据类型Data types这些类型描述进出网格的值类型说明CellValue单个单元格的值string \| number \| boolean \| null \| undefined。CellChange单个变更元组[row, column, oldValue, newValue]。传给afterChange和beforeChange。RowObject以普通对象表示的数据行当data是对象数组时使用。ChangeSource所有内置变更来源标识符的字符串联合如edit、loadData、UndoRedo.undo。SourceRowData任何索引转换之前的原始源数据行。ColumnDataGetterSetterFunction列data选项作为 getter/setter 函数的形态。使用函数数据源时变更 hook 会以它作为prop传入。SelectOptionsObjectselect和autocomplete单元格类型的选项条目{ value, label }。RangeType单元格范围描述符{ from: CellCoords, to: CellCoords }。import type { CellChange, ChangeSource } from handsontable; function onAfterChange(changes: CellChange[] | null, source: ChangeSource): void { if (!changes || source loadData) return; for (const [row, col, , newValue] of changes) { console.log(Cell [${row}, ${col}] changed to, newValue); } }源码层面这些类型的精确定义位于 handsontable/src/settings.tsCellValue unknownL19文档说明它可以是任何值以支持自定义单元格数据类型但默认是string | number | boolean | undefinedRowObject是{ [prop: string]: unknown }L12-L14可携带任意属性甚至可定义__children数组支持嵌套行CellChange [number, string | number | ColumnDataGetterSetterFunction, CellValue, CellValue]L47元组中的第二项是prop——可能是属性名、列索引或在columns[].data为函数时是那个 getter/setter 函数本身ChangeSource的完整联合L52-L58包含auto、edit、loadData、updateData、populateFromArray、spliceCol、spliceRow、timeValidate、dateValidate、validateCells以及各插件来源如Autofill.fill、ContextMenu.clearColumn、CopyPaste.paste、CopyPaste.cut、UndoRedo.redo、UndoRedo.undo、ColumnSummary.set、DataProvider.revert等SourceRowData RowObject | CellValue[]L31一行源数据可以是值数组也可以是键值对象ColumnDataGetterSetterFunctionL37-L40是重载函数类型单参仅row用于读取双参row, value用于写入。实例类型Instance type类型说明HotInstancenew Handsontable()返回的 Handsontable 实例。用于标注 ref 和接受活动实例的参数。import Handsontable from handsontable; import type { HotInstance } from handsontable; let hot: HotInstance; hot new Handsontable(document.querySelector(#grid)!, { data: myData, licenseKey: non-commercial-and-evaluation, });HotInstance接口定义在 handsontable/src/core/types.ts它描述了实例的完整 API 面包括addHook/removeHook/runHooks等 hook 方法其中addHook等方法对已知 hook 名会按Events[K]精确推导回调签名对未知字符串则回退到宽松的HookCallback、getSettings()/updateSettings()、getSelectedRange()等选区方法以及更多实例方法。HotInstance与RangeType都从 handsontable/src/index.ts 对外导出。几何类Geometry classesCellCoords和CellRange是运行时类非仅类型同时也可用作类型注解导出种类说明CellCoords类一个{ row, col }坐标对。由选择与导航 API 返回。CellRange类一个{ from: CellCoords, to: CellCoords }范围。由getSelectedRange()返回。IndexMapper类行或列的索引转换器。类型化访问hot.rowIndexMapper和hot.columnIndexMapper。RangeType类型一个纯对象范围描述符用于不需要CellRange实例的 API。import { CellRange } from handsontable; function logSelection(ranges: CellRange[]): void { for (const range of ranges) { console.log(from [${range.from.row}, ${range.from.col}] to [${range.to.row}, ${range.to.col}]); } }CellCoords、CellRange从 handsontable/src/base.ts 重新导出见 handsontable/src/index.tsIndexMapper来自翻译层./translationsL212。注意CellRange是值value所以上面的import { CellRange }会保留运行时导入这点与import type的纯类型导入不同。单元格函数注册表类型Cell function registry types用这些字符串联合类型把type、renderer、editor和validator设置约束为已注册的名称类型说明CellType所有已注册单元格类型别名的联合text \| numeric \| checkbox \| ...。EditorType所有已注册编辑器别名的联合。RendererType所有已注册渲染器别名的联合。ValidatorType所有已注册验证器别名的联合。import type { ColumnSettings, CellType } from handsontable; function buildColumn(type: CellType): ColumnSettings { return { type }; }这些联合类型是由各注册表模块的类型别名typeof推导出来的CellType定义于 handsontable/src/cellTypes/registry.tstypeof AUTOCOMPLETE_TYPE | typeof CHECKBOX_TYPE | typeof DATE_TYPE | ...EditorType于 handsontable/src/editors/index.tsRendererType于 handsontable/src/renderers/index.ts。因此当你通过registerCellType()/registerEditor()/registerRenderer()/registerValidator()注册自定义项时联合类型会随注册表声明同步演进——这是注册表驱动类型设计的体现。编辑器基类类型Editor base type类型说明BaseEditorInstanceBaseEditor类的类型。用于在自定义编辑器代码中标注参数和返回值。Hooks 注册表类型Hooks registry type类型说明HooksRegistry描述静态的Handsontable.hooks对象如.getRegistered()。在把 hooks 注册表作为类型化参数传递时很有用。import type { HooksRegistry } from handsontable; function listHooks(hooks: HooksRegistry): string[] { return hooks.getRegistered(); }HooksRegistry从 handsontable/src/base.ts 导出见 handsontable/src/index.ts。主题类型Theme types这些类型在使用主题 APIthemeName选项或构建自定义主题时相关类型说明ThemeConfigregisterTheme()的完整配置对象。ThemeParams创建主题实例的构造参数。ThemeBuilder主题工厂返回的 builder 对象。ThemeColorSchemelight \| dark \| auto。ThemeColorsConfig主题配置内的颜色 token 覆盖。ThemeDensityConfig行高与单元格内边距 token 覆盖。ThemeDensitySizes密度配置项内的数值尺寸。ThemeIconsConfig图标 token 覆盖。ThemeLightDarkValue带独立亮/暗变体的 token 值。ThemeSizingConfig字体与间距 token 覆盖。ThemeTokenValue单个设计 token 值。ThemeTokensConfigThemeConfig内部使用的完整 token 映射。BaseTheme所有内置主题继承的基础主题对象。仓库中主题系统的实现位于 handsontable/src/themes 目录内置主题的 CSS 产物通过build:themes-css/build:themes-umd等脚本构建见 handsontable/package.json。Overlay 类型Overlay type类型说明OverlayType所有 Walkontable overlay 标识符的字符串联合top \| bottom \| left \| right \| ...。在高级渲染定制中很有用。OverlayType的精确定义在 handsontable/src/3rdparty/walkontable/src/types.tsinline_start | top | top_inline_start_corner | bottom | bottom_inline_start_corner | master。可以看到它采用逻辑/物理方向混合命名inline_start、master实际取值以源码为准。公共 API 的隐式类型化Implicit typing上面列出的类型是你在需要显式导入时才用的——即当你需要为自己的变量、参数或返回值标注类型时。公共 API 的其余部分——插件、编辑器、渲染器、验证器、单元格类型以及Handsontable类本身——都自带 TypeScript 声明。导入值的同时就会自动获得完整的类型安全和 IDE 自动补全无需额外导入类型// 无需类型导入 -- ContextMenu 已完全类型化。 import { ContextMenu } from handsontable/plugins; // 无需类型导入 -- AutocompleteEditor 已完全类型化。 import { AutocompleteEditor } from handsontable/editors; // 无需类型导入 -- numericRenderer 已完全类型化。 import { numericRenderer } from handsontable/renderers; // 无需类型导入 -- Handsontable 类及其实例方法已完全类型化。 import Handsontable from handsontable; const hot new Handsontable(container, { licenseKey: non-commercial-and-evaluation }); hot.loadData(myData); // IDE 自动补全和类型检查在这里生效。上文类型参考中的显式import type { ... }模式只在值不在当前作用域内、需要把类型单独用作注解时才必要。仓库的exports映射也为子路径提供了声明./plugins/*/index.*、./editors/*/index.*、./renderers/*/index.*、./cellTypes/*/index.*等都会随构建产物一起发布见 handsontable/package.json。值得补充的是这些声明的正确性由专门的类型测试type tests守护仓库在handsontable/src下有 69 个*.types.ts文件如 handsontable/src/tests/public-types.types.ts配合test:types脚本handsontable/package.json在 CI 中编译验证——它们不产生运行时行为而是确保每个公开类型在真实使用场景下能通过类型检查。例如 handsontable/src/core/settings.ts 中提到的_strippedWidthTyped、_columnNamedOptionsTyped、_hotColumnGetValueFn等类型测试就专门守护RemoveIndexSignature与ColumnSettings的类型行为。常见模式Common patterns类型化设置对象Type the settings object直接给 settings 标注类型让 TypeScript 校验每一个选项import type { GridSettings } from handsontable; const settings: GridSettings { data: employees, colHeaders: [Name, Department, Hire date], columns: [ { data: name }, { data: department }, { data: hireDate, type: date, dateFormat: { year: numeric, month: 2-digit, day: 2-digit } }, ], licenseKey: non-commercial-and-evaluation, };使用Events类型化 hook 回调Events把每个 hook 名映射到其回调签名。用Events[hookName]提取特定回调类型import type { Events, CellChange, ChangeSource } from handsontable; const onAfterChange: Events[afterChange] (changes: CellChange[] | null, source: ChangeSource) { if (!changes) return; console.log(source, changes); }; hot.addHook(afterChange, onAfterChange);得益于HotInstance.addHook的重载设计见 handsontable/src/core/types.ts当 hook 名是已知的keyof Events时回调参数会被精确推导即使不手动标注addHook(afterChange, cb)也能获得参数补全。类型化自定义渲染器Type a custom renderer自定义渲染器接收类型化的CellProperties参数import Handsontable from handsontable; import type { CellProperties, HotInstance, GridSettings } from handsontable; function statusRenderer( hotInstance: HotInstance, TD: HTMLTableCellElement, row: number, col: number, prop: string | number, value: string, cellProperties: CellProperties ): void { Handsontable.renderers.TextRenderer(hotInstance, TD, row, col, prop, value, cellProperties); TD.style.color value Active ? green : red; }注意CellProperties比CellMeta多出渲染期字段row、col、instance、visualRow、visualCol、prop见 handsontable/src/settings.ts这正是渲染器签名里第七个参数的类型。更完整的自定义渲染器写法可参考单元格渲染器指南。类型化自定义编辑器Type a custom editor继承BaseEditorInstance实际使用中常直接继承某个内置编辑器类获得完整的 IDE 支持import { TextEditor } from handsontable/editors; import type { GridSettings } from handsontable; class RatingEditor extends TextEditor { override getValue(): string { return this.TEXTAREA?.value ?? ; } override setValue(newValue: string): void { if (this.TEXTAREA) { this.TEXTAREA.value newValue; } } } const settings: GridSettings { columns: [{ editor: RatingEditor as unknown as string }], licenseKey: non-commercial-and-evaluation, };TextEditor等编辑器类从handsontable/editors导入自带完整类型见 handsontable/src/editors/index.ts 处的导出。关于自定义编辑器的完整流程可参考单元格编辑器指南。在 React ref 中类型化 HOT 实例HotTable暴露的 ref 类型是HotTableRef而非HotInstance——需要通过hotRef.current?.hotInstance读取 Handsontable 实例。wrapper 把网格选项作为独立 props 接收所以没有settingsprop——把可复用的设置对象类型化为HotTableProps再展开到HotTable上。更多实例 ref 的用法见 React methods。import { useRef } from react; import { HotTable } from handsontable/react-wrapper; import type { HotTableRef, HotTableProps } from handsontable/react-wrapper; export function Grid() { const hotRef useRefHotTableRef(null); const settings: HotTableProps { data: myData, licenseKey: non-commercial-and-evaluation, }; const selectFirstCell () { hotRef.current?.hotInstance?.selectCell(0, 0); }; return ( HotTable ref{hotRef} {...settings} / ); }在 Angular 中类型化 HOT 实例import { Component, ViewChild } from angular/core; import { HotTableComponent, HotTableModule, GridSettings } from handsontable/angular-wrapper; Component({ standalone: true, imports: [HotTableModule], template: hot-table [settings]gridSettings /, }) export class GridComponent { ViewChild(HotTableComponent) hotTable!: HotTableComponent; readonly gridSettings: GridSettings { data: myData, licenseKey: non-commercial-and-evaluation, }; }通过hotTable.hotInstance读取 Handsontable 实例。在 Vue ref 中类型化 HOT 实例script setup langts import { ref } from vue; import { HotTable } from handsontable/vue3; import type { GridSettings } from handsontable; const hotRef refInstanceTypetypeof HotTable | null(null); const settings: GridSettings { data: myData, licenseKey: non-commercial-and-evaluation, }; /script template HotTable refhotRef :settingssettings / /templateref 被类型化为HotTable组件类型通过hotRef.value?.hotInstance读取HotInstance。小结与延伸阅读Handsontable 的类型体系可以概括为三层入口层handsontable/handsontable/base两个入口提供相同类型、显式类型层本文类型参考中列出的配置、数据、实例、几何、注册表、主题、Overlay 类型需要时才import type、隐式类型层插件、编辑器、渲染器等值导入即带类型。声明文件由最新 TypeScript 编译后降级到 TS 5.1 兼容并由 69 个*.types.ts类型测试持续守护。继续深入可参考模块化构建Modules —— 了解handsontable/base入口对应的按需注册模块机制自定义插件Custom plugins单元格编辑器Cell editor单元格渲染器Cell renderer类型声明的核心源码handsontable/src/settings.ts、handsontable/src/core/settings.ts、handsontable/src/core/types.ts、handsontable/src/index.ts声明降级机制handsontable/scripts/downlevel-dts.mjs类型测试示例handsontable/src/tests/public-types.types.ts赞分享前端UI组件【免费下载链接】handsontableJavaScript Data Grid / Data Table with a Spreadsheet Look Feel. Works with React, Angular, and Vue. Supported by the Handsontable team ⚡项目地址https://gitcode.com/gh_mirrors/ha/handsontable点击查看免费下载相关推荐Apollo-CustomApiCredentials的未来路线图即将到来的功能和改进Apollo CustomApiCredentials的未来路线图即将到来的功能和改进 Apollo CustomApiCredentials是一个让您在ApFastify 与 TypeScript 完全指南类型系统、泛型路由与插件类型安全实战Fastify 与 TypeScript 完全指南类型系统、泛型路由与插件类型安全实战 Fastify 内核使用纯 JavaScript 编写其类型系统在后端Web框架WebdriverIO TypeScript 配置完全指南tsx 编译、类型安全与框架类型声明WebdriverIO TypeScript 配置完全指南tsx 编译、类型安全与框架类型声明 WebdriverIO 作为面向 Node.js 的下一代浏览测试质量保障上一篇Newtonsoft.Json 序列化与反序列化完全指南下一篇如何完整备份微信聊天记录WeChatMsg三步导出终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表