Skip to content

finding(plugin-dashboard): DashboardRenderer 读 widget.datasetas any 及其理由注释已过期 —— DashboardWidgetSchema 在 spec 17.0.0 上已声明 dataset / values #5067

Description

@yinlianghui

发现于 #5015 的实施(为重写 README 的 TypeScript 示例,对 DashboardWidgetSchema 逐键做了编译探针,顺带量到这条)。Filed unassigned, not claiming。观察级 —— 今天没有用户会撞上:as any 只是让一个已经合法的读取绕过类型系统,行为与收窄后完全一致,所以打 finding、不打 pm:queue,定级交分诊。

现象

packages/plugin-dashboard/src/DashboardRenderer.tsx:524-528:

// ADR-0021 — a widget bound to a semantic-layer dataset renders through
// the governed queryDataset path (DatasetWidget) instead of the inline
// object-aggregate schema. `as any` because the bundled DashboardWidget
// type gains `dataset` only after objectui bumps @objectstack/spec.
const datasetBound = !!(widget as any).dataset;

注释给出的理由是「dataset 要等 objectui 把 @objectstack/spec 升上去才会出现在类型上」。这个条件已经满足:仓里装的是 @objectstack/spec@17.0.0,其 DashboardWidgetSchema 已声明 datasetvalues,而 packages/types/src/complex.ts:676DashboardWidgetSchema extends Omit< Partial< SpecDashboardWidget >, 'type' | 'options' | 'chartConfig' | 'filter' > 把它们直接继承进来 —— dataset 不在 Omit 名单里。

对构建产物 packages/types/dist/index.d.tsstrict 编译,下面这段零诊断:

import type { DashboardWidgetSchema } from '@object-ui/types';
export const boundKpi: DashboardWidgetSchema = {
  id: 'kpi_invoices',
  type: 'metric',
  title: 'Invoices',
  dataset: 'invoices',
  values: ['count'],
  colorVariant: 'success',
};

也就是说 widget.dataset 现在直接读就能通过类型检查,as any 是纯粹的多余收缩 —— 而且是有害的多余:as any 之后 .dataset 的类型是 any,若将来 spec 把 dataset 的形状改掉(比如从 string 变成对象),这一处不会红。

影响面

同文件里 as any 读 widget 键的还有 :539(widget as any).data那一处不同:data 确实不在 DashboardWidgetSchema 上(spec 与 objectui 的覆写都没声明它),所以它是「读一个未声明的键」,不是过期的 cast —— 若真要收窄,得先裁 data 该不该进契约,与本单不是一件事。本单主张 :528dataset 这一处及其注释。

未量:values 是否也有类似的 as any 读取点(本单只核了 dataset 的这一处)。

复核方式

sed -n '520,545p' packages/plugin-dashboard/src/DashboardRenderer.tsx
sed -n '676,680p' packages/types/src/complex.ts
grep -n "dataset: z.ZodString" node_modules/.pnpm/@objectstack+spec@*/node_modules/@objectstack/spec/dist/ui/index.d.ts
grep -rn "widget as any" packages/plugin-dashboard/src/DashboardRenderer.tsx

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions