@@ -49,8 +49,19 @@ export default attributes;
4949
5050Three things to notice:
5151
52- - ** ` @generates ModeBar ` ** — declares the canonical public type name. The
53- ` .d.ts ` generator uses this to name the output.
52+ - ** ` @generates ModeBar ` ** — declares the public type name. The ` .d.ts `
53+ generator uses this to name the output. Naming conventions:
54+
55+ | Category | Convention | Examples |
56+ | ---| ---| ---|
57+ | Components | PascalCase of the concept | ` ModeBar ` , ` ColorBar ` , ` Slider ` , ` RangeSelector ` |
58+ | Traces | ` <TraceName>Data ` | ` PieData ` , ` SankeyData ` , ` CandlestickData ` |
59+ | Layout | ` Layout ` | |
60+
61+ If the generated type needs hand-written refinements, use a ` *Generated `
62+ suffix instead (e.g. ` @generates ModeBarGenerated ` ) so the hand-written
63+ file can extend it under the original public name. See
64+ [ Layering hand-written refinements] ( #layering-hand-written-refinements ) .
5465- ** ` as const satisfies AttributeMap ` ** — ` as const ` preserves literal types
5566 like ` values: ['v', 'h'] ` ; ` satisfies AttributeMap ` validates structure
5667 without widening.
@@ -118,10 +129,10 @@ export interface ModeBar {
118129export type { ModeBar } from ' ../generated/components/modebar' ;
119130```
120131
121- If the hand-written type was richer than the schema (e.g. used a narrowed
122- union where the schema says ` string ` ), document the gap in a comment or
123- file an issue. Do not silently lose ergonomics — either improve the schema
124- (add ` values: [...] ` ) or layer a hand-written refinement on top .
132+ If the hand-written type was richer than the schema (e.g. a narrowed union
133+ where the schema says ` string ` , or extra non-schema fields), don't silently
134+ lose those — see
135+ [ Layering hand-written refinements ] ( #layering-hand-written-refinements ) .
125136
126137### 7. Verify
127138
@@ -158,8 +169,7 @@ for the canonical example. The full conversion changed:
158169 (with ` as const satisfies AttributeMap ` and ` @generates ModeBar ` )
159170- ` .default ` added to ` require('./attributes') ` in ` index.js ` and ` defaults.js `
160171- The hand-written ` ModeBar ` interface in ` src/types/core/layout.d.ts ` was
161- removed and replaced with
162- ` export type { ModeBar } from '../generated/components/modebar'; `
172+ replaced with a re-export from the generated file
163173
164174Schema output verified byte-identical (2547 bytes) before and after the
165175conversion.
@@ -192,6 +202,51 @@ based on an older schema. Order of operations:
1922024 . ** If the schema has fields the hand-written type lacked** , that's a free
193203 coverage win — accept the generated type.
194204
205+ ## Layering hand-written refinements
206+
207+ When the generated type is complete, a simple re-export is all you need
208+ (see step 6). But when the hand-written type was richer than the schema —
209+ narrower unions, extra non-schema fields, etc. — use the ` *Generated `
210+ suffix pattern so the hand-written file can extend the generated type.
211+
212+ First, change the ` @generates ` tag to use a ` *Generated ` suffix:
213+
214+ ``` ts
215+ // src/components/modebar/attributes.ts
216+ /**
217+ * @generates ModeBarGenerated
218+ */
219+ ```
220+
221+ Then in the hand-written file, extend it under the original public name.
222+ The ` extends ` brings all schema-derived fields along; the body only
223+ contains what the schema can't express:
224+
225+ ``` ts
226+ // src/types/core/layout.d.ts
227+ import type { ModeBarGenerated } from ' ../generated/components/modebar' ;
228+
229+ export interface ModeBar extends ModeBarGenerated {
230+ // Schema says `string`; narrow to the known button set.
231+ remove: ModeBarDefaultButtons | ModeBarDefaultButtons [];
232+
233+ // Not in the schema — runtime-only convenience field.
234+ _buttons? : HTMLElement [];
235+ }
236+ ```
237+
238+ Consumers still write ` import type { ModeBar } from 'plotly.js' ` — the
239+ ` *Generated ` intermediate is an internal detail.
240+
241+ ** When to refine vs. when to fix the schema:**
242+
243+ - If a field's type is too wide (e.g. ` string ` instead of a union), prefer
244+ adding ` values: [...] ` to the schema so the generated type is correct by
245+ construction and the simple re-export path works.
246+ - If the refinement is about non-schema concerns (runtime-only fields,
247+ narrowing for DX, overloaded method signatures), use the ` *Generated `
248+ extend pattern.
249+
195250## Order of conversion (for parallel work)
196251
197252Pick from this priority list. Lower-numbered items are smaller / simpler.
0 commit comments