Repository navigation
ImportWizardProps.dataSource is required, but every read of it in the component is defensive #4320
Description
Activity
Findings triage (first grade): HOLD —
findingstays.- Premise re-verified @
origin/main6044d13:dataSource: anydeclared required atpackages/plugin-grid/src/ImportWizard.tsx:292, and the defensive style is measurably the component's real contract — 7 hits of thePartial<DataSource> | undefinedcast pattern in the file, matching the card's site list. - Why hold: the mismatch fails safe (a stricter declaration can only reject calls the component would survive), no user meets it, and the fixture cost is already paid in PR feat(plugin-grid): declare the host-driven external-pagination contract and type-check its tests (#4277, #4040) #4297. The residual value is the contract question — optional-and-degrading vs required-and-unguarded — which is a design pick on a public exported interface, not mechanical work. The card's own analysis; endorsed.
- Either resolution should also replace
anywithDataSource— the fivePartial<DataSource>casts are the declaration admitting the type it wants; noted so the eventual fix doesn't decide only half the question. - Restart conditions: ① the next deliberate touch of
ImportWizardProps/plugin-grid public types (fold this in as a declared scope item); ② a real caller wanting the dataSource-less embed (that makes "optional" the measured answer and this a queue card); ③ the [P2] objectui: every package type-checks its tests or declares why not — and guards must prove they can fail (measured: 355 errors across 19 packages) #4040 program reaching plugin-grid's public-surface pass. - Dedup: [P2] objectui: every package type-checks its tests or declares why not — and guards must prove they can fail (measured: 355 errors across 19 packages) #4040 (test-tsc program, in flight) explicitly stops-and-files on public types — this card is that protocol output; no other card covers
ImportWizardProps.
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- Premise re-verified @
Concentrated finding round (unified triage seat, 2026-08-17): closed not planned. The declaration being stricter than the implementation fails safe (can only reject calls the component would survive), no user meets it, and the one cost it ever exacted — a test fixture line — is already paid and pinned. Re-declaring
dataSourceoptional is a public-interface change on a published package with no consumer asking for it; the record of "the defensive reads are the real contract" is what this card is for, and it survives in the closed state.Reopen trigger: a second consumer trips on the required declaration, or a
dataSource-less embed becomes a supported product shape worth declaring — then the fix isdataSource?:plus narrowing the internal reads, in one PR. Maintainer veto: reopen is free.
Generated by Claude Code
Found while wiring
@object-ui/plugin-grid's tests intotscfor #4040 (tranche 2, PR #4297). Recorded rather than changed: it is a public exported interface, and #4040's standing rule is to stop and file when a public type looks wrong rather than guess at it.What the compiler said
ImportWizardProps.dataSource(packages/plugin-grid/src/ImportWizard.tsx:292) is declareddataSource: any— required.src/__tests__/importMissingRequiredHint.test.tsxomitted it, which is what the newly-compiled test project reported:PR #4297 fixed the fixture (it passes a capability-free
{}), which is the right fix for that test and is where the matter ends for #4040.The observation
The fixture was omitting it and the wizard rendered fine — because every read of
dataSourceinside the component is guarded. There is no unguarded dereference anywhere in the file:const ds = dataSource as Partial< DataSource > | undefined;— three times (:1432,:1632,:1883)(dataSource as { listImportMappings?: … } | undefined)?.listImportMappings(:1673)if (dataSource?.create) await dataSource.create(…)(:1861)typeof (dataSource as Partial< DataSource > | undefined)?.listImportJobs === 'function'(:2188), and the same shape forimportRecords(:2303) andcancelImportJob(:2353)So the implementation's real contract is "optional, and every capability on it is optional too" — the wizard degrades from the server import path to the per-row
createloop to nothing at all — while the declaration says "required". The two disagree, and the ones written in the defensive style are the ones the code actually obeys.Why this is an observation and not a defect
No user meets it. Every real caller passes a data source, and the declaration being stricter than the implementation fails safe: it can only reject a call the component would have survived, never accept one it cannot. It cost one test fixture a line, and that line is now written.
It is worth a card anyway because the mismatch is the kind that decides a later question wrongly: someone reading
dataSource: anyas required will not know that adataSource-less embed is a supported shape (and someone reading the guards will not know whether they are load-bearing or superstition). Both readings are currently defensible from the source, which is the actual problem.If it is ever picked up
Two coherent resolutions, and the choice is a contract call, not execution:
dataSource?: DataSource) — matches the implementation, and lets a caller mount the wizard for its parse/mapping steps alone. Widens the accepted surface.Either way
anyis worth replacing withDataSource: the component already casts toPartial< DataSource >at five sites to get any checking back, which is the declaration admitting the type it wants.Refs #4040, #4297.