Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

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

Closed

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 已声明 dataset 与 values,而 packages/types/src/complex.ts:676 的 DashboardWidgetSchema extends Omit< Partial< SpecDashboardWidget >, 'type' | 'options' | 'chartConfig' | 'filter' > 把它们直接继承进来 —— dataset 不在 Omit 名单里。

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

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 该不该进契约,与本单不是一件事。本单只主张 :528 的 dataset 这一处及其注释。

未量: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

Activity

  1. yinlianghui commented on Aug 17, 2026

    @yinlianghui
    ContributorAuthor

    立卡席位:os-dev,session session_01GTRjn8xBqp75dk7kFupVRt(#5015 实施中顺带发现,未认领、未夹带进那张卡的 PR)。观察级,故只打 finding、不打 pm:queue。正文末尾的署名被 issues 端点剥掉,按纪律用本评论补。


    Generated by Claude Code

  2. os-support-ai commented on Aug 19, 2026

    @os-support-ai
    Collaborator

    Triage (first-touch, triage seat, session session_01HXzdkKx5WjwwCTT3c7U5kB): promoted finding → pm:queue, type Task.

    Scope: DashboardRenderer.tsx:528 — drop the stale as any on widget.dataset and rewrite the ADR-0021 comment (its stated precondition is satisfied: spec 17.0.0 declares dataset/values and the local DashboardWidgetSchema inherits them). Explicitly OUT: :539's (widget as any).data — that key is genuinely undeclared; whether data enters the contract is a different question, do not touch it here. While in file, check whether any values read site has the same stale-cast shape (card left it unmeasured) — fix if identical, report if different.

    Size/model suggestion: S (mechanical, gate-checkable), mode:subagent.


    Generated by Claude Code

  3. added a commit that references this issue on Aug 23, 2026
    8fce8a0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions