-
Notifications
You must be signed in to change notification settings - Fork 0
feat(type-aliases): add support for generic type aliases #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The changes in this commit add support for parsing and generating code for generic type aliases in the validation schema codegen tool. The main changes are: 1. Modify the `index.ts` file to check if any interfaces or type aliases have generic type parameters. 2. Implement the `parseGenericTypeAlias` method in the `TypeAliasParser` class to handle the parsing and code generation for generic type aliases. 3. Add a new method `createGenericTypeAliasFunction` to generate the TypeBox function definition for the generic type alias. 4. Implement the `addGenericTypeAlias` method to add the generic type alias declaration to the output file. These changes allow the validation schema codegen tool to properly handle and generate code for generic type aliases, which is an important feature for users who need to define complex schema types.
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe PR adds unified generic-type processing via a new GenericTypeUtils, extends generic detection to type aliases, refactors interface and type-alias parsers to emit arrow-function factories plus Static aliases, moves generic function generation out of handlers, introduces readonly handling for utility types and readonly arrays/tuples, updates import logic for TSchema, and adds/updates tests and docs. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Developer
participant Printer as TypeBoxPrinter
participant Parsers as Interface/TypeAlias Parsers
participant Utils as GenericTypeUtils
participant Handlers as TypeBox Handlers
Dev->>Printer: printNode(node)
Printer->>Parsers: parse(node)
alt Generic type alias or interface
Parsers->>Handlers: request TypeBox expression for body
Handlers-->>Parsers: TypeBox expression (object/composite)
Parsers->>Utils: createGenericArrowFunction(typeParams, expr)
Utils-->>Parsers: ArrowFunction (text)
Parsers->>Utils: addTypeBoxVariableStatement(name, arrowText)
Parsers->>Utils: addGenericTypeAlias(name, typeParams, printer)
else Non-generic
Parsers->>Handlers: request TypeBox expression
Handlers-->>Parsers: TypeBox expression
Parsers->>Utils: addTypeBoxVariableStatement(name, exprText)
end
sequenceDiagram
autonumber
participant Index as src/index.ts
participant AST as AST Traversal
participant Imports as Import Builder
Index->>AST: scan files for generics (interfaces + type aliases)
AST-->>Index: hasGenericTypes (bool)
alt hasGenericTypes == true
Index->>Imports: add `TSchema` as type-only import
else
Note over Index: no TSchema import added
end
sequenceDiagram
autonumber
participant Handlers as TypeBoxTypeHandlers
participant Node as TS TypeNode
participant RRef as ReadonlyTypeHandler
participant RArr as ReadonlyArrayTypeHandler
Handlers->>Node: dispatch(node)
alt Utility type `Readonly<T>`
Handlers->>RRef: handle(type reference)
RRef-->>Handlers: Type.Readonly(innerConverted)
else Modifier `readonly` on arrays/tuples
Handlers->>RArr: handle(readonly modifier)
RArr-->>Handlers: Type.Readonly(innerArrayExpr)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. 📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (2)
💤 Files with no reviewable changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ARCHITECTURE.md (1)
26-31: Minor grammar/punctuation fixes in “Supported TypeScript Constructs”.Add periods for consistency and fix hyphenation.
-- **Generic Types**: Generic interfaces and type aliases with type parameters and proper constraint handling +- **Generic Types**: Generic interfaces and type aliases with type parameters and proper constraint handling. -- **Complex Types**: Union and intersection types, nested object structures, template literal types +- **Complex Types**: Union and intersection types, nested object structures, and template literal types. -- **Utility Types**: Built-in support for Pick, Omit, Partial, Required, Record, and other TypeScript utility types +- **Utility Types**: Built-in support for Pick, Omit, Partial, Required, Record, and other TypeScript utility types. -- **Advanced Features**: Conditional types, mapped types, keyof operators, indexed access types +- **Advanced Features**: Conditional types, mapped types, keyof operators, and indexed access types.
🧹 Nitpick comments (6)
tests/utils.ts (1)
6-11: Prefer building import specifiers via an array to avoid spacing/comma edge cases.Construct the import list programmatically and join with ", " to remove manual spacing logic and reduce risk of malformed imports.
-const typeboxImport = (withTSchema: boolean, withReadonly: boolean) => { - const readonly = withReadonly ? ' Readonly,' : '' - const tschema = withTSchema ? ', type TSchema' : '' - - return `import { Type,${readonly} type Static${tschema} } from "@sinclair/typebox";\n` -} +const typeboxImport = (withTSchema: boolean, withReadonly: boolean) => { + const specs = ['Type', ...(withReadonly ? ['Readonly'] : []), 'type Static', ...(withTSchema ? ['type TSchema'] : [])] + return `import { ${specs.join(', ')} } from "@sinclair/typebox";\n` +}Also applies to: 10-10
ARCHITECTURE.md (1)
39-47: Wording nit: “Output File Creation” sentence reads awkwardly.Tighten phrasing.
-3. **Output File Creation**: Creates a new output file with necessary `@sinclair/typebox` imports using `createOutputFile` +3. **Output File Creation**: Creates a new output file with the required `@sinclair/typebox` imports via `createOutputFile`.src/utils/generic-type-utils.ts (2)
75-83: Minor: NodeArray creation is unnecessary.Pass arrays directly; factory will wrap as needed.
- return ts.factory.createArrowFunction( - undefined, - ts.factory.createNodeArray(functionTypeParams), - functionParams, + return ts.factory.createArrowFunction( + undefined, + functionTypeParams, + functionParams, undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), functionBody, )
142-150: Type parameter printing via printer is fine; ensure stable whitespace.No functional issue, but consider passing structures instead of preprinted strings to avoid formatting differences across TS versions.
tests/handlers/typebox/interfaces.test.ts (2)
304-329: Boolean-flag readability in helpers.
formatWithPrettier(..., true, true, true)is hard to parse. Prefer an options bag.-export const formatWithPrettier = ( - input: string, - addImport: boolean = true, - withTSchema: boolean = false, - withReadonly: boolean = false, -): string => { +export interface FormatOptions { addImport?: boolean; withTSchema?: boolean; withReadonly?: boolean } +export const formatWithPrettier = (input: string, opts: FormatOptions = {}): string => { + const { addImport = true, withTSchema = false, withReadonly = false } = opts const code = addImport ? `${typeboxImport(withTSchema, withReadonly)}${input}` : input return synchronizedPrettier.format(code, prettierOptions) }And update calls accordingly.
331-363: Confirm generic ReturnType syntax in expectations.If you adopt
(typeof Name)<T>in codegen (see utils comment), align test expectations fromReturnType<typeof Name<T>>toReturnType<(typeof Name)<T>>.I can update tests after you decide on the canonical syntax.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
ARCHITECTURE.md(4 hunks)src/index.ts(2 hunks)src/parsers/parse-interfaces.ts(3 hunks)src/parsers/parse-type-aliases.ts(2 hunks)src/printer/typebox-printer.ts(1 hunks)src/utils/generic-type-utils.ts(1 hunks)tests/handlers/typebox/interfaces.test.ts(1 hunks)tests/utils.ts(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
tests/handlers/typebox/interfaces.test.ts (1)
tests/utils.ts (3)
createSourceFile(13-15)generateFormattedCode(28-40)formatWithPrettier(17-26)
src/parsers/parse-interfaces.ts (1)
src/utils/generic-type-utils.ts (1)
GenericTypeUtils(6-151)
src/parsers/parse-type-aliases.ts (4)
src/utils/generic-type-utils.ts (1)
GenericTypeUtils(6-151)src/utils/add-static-type-alias.ts (1)
addStaticTypeAlias(4-22)src/utils/typebox-call.ts (1)
getTypeBoxType(9-21)src/utils/typebox-codegen-utils.ts (1)
makeTypeCall(3-12)
tests/utils.ts (1)
src/index.ts (1)
generateCode(81-115)
🪛 LanguageTool
ARCHITECTURE.md
[grammar] ~27-~27: There might be a mistake here.
Context: ...arameters and proper constraint handling - Complex Types: Union and intersection ...
(QB_NEW_EN)
[grammar] ~42-~42: There might be a mistake here.
Context: ...ed TypeBox imports (including TSchema) 3. Output File Creation: Creates a new ou...
(QB_NEW_EN)
[grammar] ~192-~192: There might be a mistake here.
Context: ...matically detects type parameters using typeAlias.getTypeParameters() 2. Function Generation: Creates TypeBox f...
(QB_NEW_EN)
[grammar] ~193-~193: There might be a mistake here.
Context: ...liases with proper parameter constraints 3. TSchema Constraints: Applies TSchema...
(QB_NEW_EN)
[grammar] ~194-~194: There might be a mistake here.
Context: ...ype parameters for TypeBox compatibility 4. Static Type Generation: Generates corr...
(QB_NEW_EN)
[grammar] ~209-~209: There might be a mistake here.
Context: ...c parameters (e.g., ApiResponse<T, E>) - Nested Generic Types: Generic types th...
(QB_NEW_EN)
[grammar] ~210-~210: There might be a mistake here.
Context: ...types that reference other generic types - Utility Type Combinations: Complex com...
(QB_NEW_EN)
[grammar] ~211-~211: There might be a mistake here.
Context: ...mbinations**: Complex combinations like Partial<Readonly<Record<K, V>>> - Type Parameter Propagation: Proper han...
(QB_NEW_EN)
🔇 Additional comments (17)
tests/utils.ts (1)
17-24: Confirm callers updated for new withReadonly flag.Signature changes ripple through tests. Ensure all invocations of formatWithPrettier/generateFormattedCode pass the intended withReadonly value (especially where Readonly appears in expectations).
Also applies to: 39-40
src/utils/generic-type-utils.ts (2)
29-44: Parameter typings for generic factories look good.The value-parameter equals the type-parameter pattern (e.g.,
T: T) matches the generated API.
49-63: Constraint normalization to TSchema is correct for TypeBox compatibility.No issues spotted.
src/printer/typebox-printer.ts (2)
44-45: Switch to unifiedparseis consistent with parser refactor.Good simplification.
33-37: No obsoleteparseWithImportFlagcode
No occurrences ofparseWithImportFlagdetected in the codebase; nothing to remove.Likely an incorrect or invalid review comment.
src/index.ts (4)
17-22: LGTM: import scaffold.Defaulting to non-type import for Type and type-only for everything else is sound.
31-35: LGTM: always include Static as type-only.
36-41: LGTM: gate TSchema on generics.
89-95: LGTM: generic detection broadened to type aliases.src/parsers/parse-interfaces.ts (3)
3-3: LGTM: centralizing via GenericTypeUtils.
5-5: LGTM: import ts for printer usage.
38-39: LGTM: regular interface path uses shared variable-statement helper.src/parsers/parse-type-aliases.ts (5)
10-17: LGTM: dedupe by processedTypes.
18-26: LGTM: branch generic vs regular.
28-42: LGTM: regular type alias generation via shared utils.
44-70: LGTM: generic function expression for type aliases.The shared utility usage is correct and consistent.
71-73: TypeScript 5.9.2 supportstypeof Name<T>in type queries; keepGenericTypeUtils.addGenericTypeAliasimplementation as-is.
| ### Generic Type Support | ||
|
|
||
| The codebase provides comprehensive support for both generic interfaces and generic type aliases, enabling complex type transformations and reusable type definitions. | ||
|
|
||
| #### Generic Type Aliases | ||
|
|
||
| The `TypeAliasParser` handles both regular and generic type aliases through specialized processing: | ||
|
|
||
| 1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()` | ||
| 2. **Function Generation**: Creates TypeBox functions for generic type aliases with proper parameter constraints | ||
| 3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility | ||
| 4. **Static Type Generation**: Generates corresponding TypeScript type aliases using `Static<ReturnType<typeof TypeName<T>>>` | ||
|
|
||
| #### Generic Interface Support | ||
|
|
||
| Generic interfaces are processed similarly through the `InterfaceParser`: | ||
|
|
||
| 1. **Parameter Constraint Handling**: Converts TypeScript type parameter constraints to `TSchema` constraints | ||
| 2. **Function-Based Schema Generation**: Creates TypeBox schema functions that accept type parameters | ||
| 3. **Type Safety Preservation**: Maintains full TypeScript type safety through proper static type aliases | ||
|
|
||
| #### Complex Generic Scenarios | ||
|
|
||
| The system supports advanced generic patterns including: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consistency: Section headers and list items need terminal punctuation.
Add periods and ensure parallel phrasing in numbered lists (e.g., start with verbs).
-1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()`
-2. **Function Generation**: Creates TypeBox functions for generic type aliases with proper parameter constraints
-3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility
-4. **Static Type Generation**: Generates corresponding TypeScript type aliases using `Static<ReturnType<typeof TypeName<T>>>`
+1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()`.
+2. **Function Generation**: Creates TypeBox functions for generic type aliases with proper parameter constraints.
+3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility.
+4. **Static Type Generation**: Generates corresponding TypeScript type aliases using `Static<ReturnType<typeof TypeName<T>>>`.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ### Generic Type Support | |
| The codebase provides comprehensive support for both generic interfaces and generic type aliases, enabling complex type transformations and reusable type definitions. | |
| #### Generic Type Aliases | |
| The `TypeAliasParser` handles both regular and generic type aliases through specialized processing: | |
| 1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()` | |
| 2. **Function Generation**: Creates TypeBox functions for generic type aliases with proper parameter constraints | |
| 3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility | |
| 4. **Static Type Generation**: Generates corresponding TypeScript type aliases using `Static<ReturnType<typeof TypeName<T>>>` | |
| #### Generic Interface Support | |
| Generic interfaces are processed similarly through the `InterfaceParser`: | |
| 1. **Parameter Constraint Handling**: Converts TypeScript type parameter constraints to `TSchema` constraints | |
| 2. **Function-Based Schema Generation**: Creates TypeBox schema functions that accept type parameters | |
| 3. **Type Safety Preservation**: Maintains full TypeScript type safety through proper static type aliases | |
| #### Complex Generic Scenarios | |
| The system supports advanced generic patterns including: | |
| #### Generic Type Aliases | |
| The `TypeAliasParser` handles both regular and generic type aliases through specialized processing: | |
| 1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()`. | |
| 2. **Function Generation**: Creates TypeBox functions for generic type aliases with proper parameter constraints. | |
| 3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility. | |
| 4. **Static Type Generation**: Generates corresponding TypeScript type aliases using `Static<ReturnType<typeof TypeName<T>>>`. |
🧰 Tools
🪛 LanguageTool
[grammar] ~192-~192: There might be a mistake here.
Context: ...matically detects type parameters using typeAlias.getTypeParameters() 2. Function Generation: Creates TypeBox f...
(QB_NEW_EN)
[grammar] ~193-~193: There might be a mistake here.
Context: ...liases with proper parameter constraints 3. TSchema Constraints: Applies TSchema...
(QB_NEW_EN)
[grammar] ~194-~194: There might be a mistake here.
Context: ...ype parameters for TypeBox compatibility 4. Static Type Generation: Generates corr...
(QB_NEW_EN)
🤖 Prompt for AI Agents
In ARCHITECTURE.md around lines 184 to 207, several section headers and
numbered/list items lack terminal punctuation and inconsistent phrasing; update
headers and all list items to end with periods and make the numbered list
entries use parallel verb-led phrasing (e.g., "Detect type parameters.", "Create
TypeBox functions.", "Apply TSchema constraints.", "Generate static type
aliases.") so punctuation and grammatical structure are consistent across the
section.
| const typeReferenceWithArgs = ts.factory.createTypeReferenceNode( | ||
| ts.factory.createIdentifier(name), | ||
| typeArguments, | ||
| ) | ||
|
|
||
| const typeofExpression = ts.factory.createTypeQueryNode( | ||
| typeReferenceWithArgs.typeName, | ||
| typeReferenceWithArgs.typeArguments, | ||
| ) | ||
|
|
||
| const returnTypeExpression = ts.factory.createTypeReferenceNode( | ||
| ts.factory.createIdentifier('ReturnType'), | ||
| [typeofExpression], | ||
| ) | ||
|
|
||
| const staticTypeNode = ts.factory.createTypeReferenceNode( | ||
| ts.factory.createIdentifier('Static'), | ||
| [returnTypeExpression], | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
❓ Verification inconclusive
Potentially invalid TypeScript: typeof ${name}<T> inside ReturnType.
ReturnType<typeof A<T>> may not be accepted by all TS versions (commonly requires ReturnType<(typeof A)<T>>). This impacts generated code usability for consumers.
Option A (AST-lite string assembly, simplest and robust across TS versions):
- const returnTypeExpression = ts.factory.createTypeReferenceNode(
- ts.factory.createIdentifier('ReturnType'),
- [typeofExpression],
- )
-
- const staticTypeNode = ts.factory.createTypeReferenceNode(
- ts.factory.createIdentifier('Static'),
- [returnTypeExpression],
- )
-
- const staticType = printer.printNode(
- ts.EmitHint.Unspecified,
- staticTypeNode,
- newSourceFile.compilerNode,
- )
+ const typeArgs = typeParamNames.join(', ')
+ const staticType = `Static<ReturnType<(typeof ${name})<${typeArgs}>>>`Option B (keep AST): construct a parenthesized type around a type query, then a generic instantiation. AST for this is verbose; if you want, I can provide the exact nodes.
Please compile a small generated example with your TS baseline to confirm which form is required. If (typeof X)<T> is necessary, update tests expecting typeof X<T>.
Wrap the typeof expression in parentheses before applying type arguments. TS’s grammar only allows an EntityName after typeof (no type arguments), so ReturnType<typeof A<T>> is invalid—use ReturnType<(typeof A)<T>>. Update the AST builder to emit (typeof ${name})<…> and adjust any tests that assert the old form. (tc39.es)
🤖 Prompt for AI Agents
In src/utils/generic-type-utils.ts around lines 116 to 134, the code currently
emits ReturnType<typeof A<T>> which is invalid; change the AST construction so
the typeof query is wrapped in a parenthesized type before applying type
arguments (emit ReturnType<(typeof A)<T>>). Concretely, build the TypeQueryNode
for the identifier, then wrap it in a ParenthesizedTypeNode (use
ts.factory.createParenthesizedType or the equivalent for type nodes) and use
that parenthesized node as the target when creating the subsequent
TypeReferenceNode with type arguments; update any tests that assert the old
unparenthesized form.
| test('generics with complexity', () => { | ||
| const sourceFile = createSourceFile( | ||
| project, | ||
| ` | ||
| export type LanguageCode = string; | ||
| type LanguageRecord<V> = Partial<Readonly<Record<LanguageCode, V>>>; | ||
| `, | ||
| ) | ||
|
|
||
| expect(generateFormattedCode(sourceFile)).toBe( | ||
| formatWithPrettier( | ||
| ` | ||
| export const LanguageCode = Type.String() | ||
| export type LanguageCode = Static<typeof LanguageCode> | ||
| export const LanguageRecord = <V extends TSchema>(V: V) => Type.Partial(Readonly(Type.Record(LanguageCode, V))) | ||
| export type LanguageRecord<V extends TSchema> = Static<ReturnType<typeof LanguageRecord<V>>> | ||
| `, | ||
| true, | ||
| true, | ||
| true, | ||
| ), | ||
| ) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify that Readonly is a named export in your TypeBox version.
The expectation imports and calls Readonly(...) as a named import. Some TypeBox versions expose this under Type.Readonly. Ensure compatibility or adjust expectations.
Alternatively, confirm via docs for the target version.
🏁 Script executed:
#!/bin/bash
# Inspect installed TypeBox version and surface exports (if repo has lockfile)
rg -nP '"@sinclair/typebox"' -C2 package.json pnpm-lock.yaml package-lock.json yarn.lock || trueLength of output: 260
🌐 Web query:
Does @sinclair/typebox export a named `Readonly` (import { Readonly }) in current releases, or should `Type.Readonly` be used?
💡 Result:
Use Type.Readonly — there is no top-level named export Readonly to import. The API exposes the Readonly modifier via the Type namespace (e.g. Type.Readonly(...)) and the typings show TReadonly/Type.Readonly usage. [1][2][3]
Sources:
- type definitions showing TReadonly and Type.Readonly usage. [1]
- npm README showing Type.Readonly is a Type modifier. [2]
- GitHub discussion confirming Type.Readonly is for TS static inference and not a separate serializable
readOnlykeyword. [3]
Use Type.Readonly instead of Readonly. TypeBox only exposes the Readonly modifier under the Type namespace, so update the test in tests/handlers/typebox/interfaces.test.ts (around line 312) to call Type.Readonly(...) rather than a top-level Readonly.
🤖 Prompt for AI Agents
In tests/handlers/typebox/interfaces.test.ts around lines 304 to 329, the test
constructs a TypeBox schema using the global Readonly identifier which doesn't
exist; replace the top-level Readonly call with Type.Readonly so the generated
schema uses the TypeBox Readonly modifier (i.e. change Readonly(...) to
Type.Readonly(...)) and update any corresponding expected formatted output in
the assertion to reflect Type.Readonly in that position.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/handlers/typebox/object/interface-type-handler.ts (1)
51-64: Broken handling of extended generic types (multi-arg/nested) and built-ins.The regex only supports one type arg and emits identifiers like
Record(...)/ReadonlyArray(...)instead ofType.*, which will generate invalid code for cases likeextends Record<string, number>orextends ReadonlyArray<T>.Apply this targeted fix to robustly parse and map common built-ins while still supporting user-defined generic factories:
- private parseGenericTypeCall(typeText: string): ts.Expression | null { - const match = typeText.match(/^([^<]+)<([^>]+)>$/) - - if (match && match[1] && match[2]) { - const baseName = match[1].trim() - const typeArg = match[2].trim() - - return ts.factory.createCallExpression(ts.factory.createIdentifier(baseName), undefined, [ - this.createTypeExpression(typeArg), - ]) - } - - return null - } + private parseGenericTypeCall(typeText: string): ts.Expression | null { + const match = typeText.match(/^([^<]+)<(.+)>$/) + if (!match) return null + const baseName = match[1].trim() + const argsText = match[2].trim() + + // Split top-level comma-separated args (handles nested generics) + const args: string[] = [] + let depth = 0, start = 0 + for (let i = 0; i < argsText.length; i++) { + const c = argsText[i] + if (c === '<') depth++ + else if (c === '>') depth-- + else if (c === ',' && depth === 0) { + args.push(argsText.slice(start, i).trim()) + start = i + 1 + } + } + args.push(argsText.slice(start).trim()) + + const mapArg = (s: string) => this.createTypeExpression(s) + + switch (baseName) { + case 'Record': + if (args.length === 2) return makeTypeCall('Record', [mapArg(args[0]), mapArg(args[1])]) + break + case 'Readonly': + if (args.length === 1) return makeTypeCall('Readonly', [mapArg(args[0])]) + break + case 'ReadonlyArray': + if (args.length === 1) return makeTypeCall('Readonly', [makeTypeCall('Array', [mapArg(args[0])])]) + break + case 'Array': + if (args.length === 1) return makeTypeCall('Array', [mapArg(args[0])]) + break + case 'Partial': + case 'Pick': + case 'Omit': + case 'Required': + return makeTypeCall(baseName, args.map(mapArg)) + } + + // Fallback: call generated factory functions, e.g., Foo<T> + return ts.factory.createCallExpression( + ts.factory.createIdentifier(baseName), + undefined, + args.map((a) => this.createTypeExpression(a)), + ) + }
♻️ Duplicate comments (2)
src/index.ts (1)
11-11: Resolved: removed hasReadonly from createOutputFile signature.Matches prior feedback; call sites updated.
ARCHITECTURE.md (1)
27-30: Punctuate and parallelize list items.End bullets with periods and keep phrasing parallel.
-**Generic Types**: Generic interfaces and type aliases with type parameters and proper constraint handling +**Generic Types**: Generic interfaces and type aliases with type parameters and proper constraint handling. -**Utility Types**: Built-in support for Pick, Omit, Partial, Required, Record, Readonly, and other TypeScript utility types +**Utility Types**: Built-in support for Pick, Omit, Partial, Required, Record, Readonly, and other TypeScript utility types.
🧹 Nitpick comments (8)
src/handlers/typebox/readonly-array-type-handler.ts (1)
9-11: Use the configured method name instead of hardcoding 'Readonly'.Keeps the handler DRY and consistent with TypeOperatorBaseHandler.
- protected createTypeBoxCall(innerType: ts.Expression): ts.Expression { - return makeTypeCall('Readonly', [innerType]) - } + protected createTypeBoxCall(innerType: ts.Expression): ts.Expression { + return makeTypeCall(this.typeBoxMethod, [innerType]) + }src/handlers/typebox/object/interface-type-handler.ts (1)
81-98: Prefer AST over string parsing for heritage types.Using
typeNode.getText()is brittle for complex/nested generics. Consider switching toExpressionWithTypeArgumentsand converting via existing handlers, or at least readinggetExpression()andgetTypeArguments()to avoid text regex.Happy to refactor
collectExtendedTypesto AST-based processing if you want a follow-up PR.src/index.ts (1)
16-26: Minor: explicit type on namedImports is unnecessary.TS can infer
{ name: string; isTypeOnly: boolean }[]; optional to drop for brevity.tests/handlers/typebox/readonly.test.ts (1)
119-152: Add coverage for interface inheritance with built-ins.Please add tests for:
interface I extends Record<string, number> {}interface J<T> extends ReadonlyArray<T> {}These would have caught the
parseGenericTypeCallissues.tests/handlers/typebox/interface-generics-runtime-binding.test.ts (1)
74-117: Intentional failing test will break CI. Mark as todo/skip or implement support before merge.If this PR is not making it pass, avoid red builds.
Apply this minimal diff to keep the test as a tracked todo without failing:
- test('should fail with current implementation - demonstrates the issue', () => { + test.todo('GenericContainer<T, U> should generate a generic arrow function wrapper'); - // This test is designed to fail with the current implementation - // to show that we need to fix the generic interface handling - const sourceFile = createSourceFile( - project, - ` - interface GenericContainer<T, U> { - first: T; - second: U; - metadata: { - created: string; - updated: string; - }; - } - `, - ) - - const result = generateFormattedCode(sourceFile, true) - // ... - expect(result).toBe( - formatWithPrettier( - ` - export const GenericContainer = <T extends TSchema, U extends TSchema>(T: T, U: U) => Type.Object({ - first: T, - second: U, - metadata: Type.Object({ - created: Type.String(), - updated: Type.String(), - }), - }); - - export type GenericContainer<T extends TSchema, U extends TSchema> = Static<ReturnType<typeof GenericContainer<T, U>>>; - `, - true, - true, - ), - ) - }) + // (implementation to be added in a follow-up PR)ARCHITECTURE.md (3)
41-46: Add terminal periods to flow steps.-2. **Generic Type Detection**: Checks for generic interfaces and type aliases to determine required TypeBox imports (including `TSchema`) +2. **Generic Type Detection**: Checks for generic interfaces and type aliases to determine required TypeBox imports (including `TSchema`).
116-118: Terminate parser bullets with periods.-1. **InterfaceParser**: <mcfile name="parse-interfaces.ts" path="src/parsers/parse-interfaces.ts"></mcfile> - Handles both regular and generic interfaces using the unified `GenericTypeUtils` flow for consistency with type aliases -2. **TypeAliasParser**: <mcfile name="parse-type-aliases.ts" path="src/parsers/parse-type-aliases.ts"></mcfile> - Processes both regular and generic type alias declarations using `GenericTypeUtils.createGenericArrowFunction` +1. **InterfaceParser**: <mcfile name="parse-interfaces.ts" path="src/parsers/parse-interfaces.ts"></mcfile> - Handles both regular and generic interfaces using the unified `GenericTypeUtils` flow for consistency with type aliases. +2. **TypeAliasParser**: <mcfile name="parse-type-aliases.ts" path="src/parsers/parse-type-aliases.ts"></mcfile> - Processes both regular and generic type alias declarations using `GenericTypeUtils.createGenericArrowFunction`.
139-159: Clarify Readonly coverage and keep bullets concise.Minor wording for precision.
-Registered as a fallback handler to handle complex readonly patterns +Registered as a fallback handler for complex readonly-array patterns.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (12)
ARCHITECTURE.md(6 hunks)src/handlers/typebox/object/interface-type-handler.ts(2 hunks)src/handlers/typebox/readonly-array-type-handler.ts(1 hunks)src/handlers/typebox/readonly-type-handler.ts(1 hunks)src/handlers/typebox/typebox-type-handlers.ts(3 hunks)src/index.ts(2 hunks)src/parsers/parse-interfaces.ts(3 hunks)tests/handlers/typebox/generics.test.ts(1 hunks)tests/handlers/typebox/interface-generics-consistency.test.ts(1 hunks)tests/handlers/typebox/interface-generics-runtime-binding.test.ts(1 hunks)tests/handlers/typebox/interfaces.test.ts(0 hunks)tests/handlers/typebox/readonly.test.ts(1 hunks)
💤 Files with no reviewable changes (1)
- tests/handlers/typebox/interfaces.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/parsers/parse-interfaces.ts
🧰 Additional context used
🧬 Code graph analysis (8)
tests/handlers/typebox/readonly.test.ts (1)
tests/utils.ts (3)
createSourceFile(12-14)generateFormattedCode(26-37)formatWithPrettier(16-24)
src/handlers/typebox/readonly-array-type-handler.ts (1)
src/utils/typebox-codegen-utils.ts (1)
makeTypeCall(3-12)
tests/handlers/typebox/interface-generics-consistency.test.ts (2)
tests/utils.ts (3)
createSourceFile(12-14)generateFormattedCode(26-37)formatWithPrettier(16-24)tests/handlers/typebox/interfaces.test.ts (5)
sourceFile(235-263)sourceFile(205-233)project(5-305)sourceFile(72-107)sourceFile(43-70)
src/handlers/typebox/typebox-type-handlers.ts (1)
src/handlers/typebox/readonly-array-type-handler.ts (1)
ReadonlyArrayTypeHandler(5-12)
tests/handlers/typebox/generics.test.ts (2)
tests/utils.ts (3)
createSourceFile(12-14)generateFormattedCode(26-37)formatWithPrettier(16-24)tests/handlers/typebox/interfaces.test.ts (2)
sourceFile(235-263)sourceFile(72-107)
tests/handlers/typebox/interface-generics-runtime-binding.test.ts (1)
tests/utils.ts (3)
createSourceFile(12-14)generateFormattedCode(26-37)formatWithPrettier(16-24)
src/handlers/typebox/object/interface-type-handler.ts (1)
src/utils/typebox-codegen-utils.ts (1)
makeTypeCall(3-12)
src/handlers/typebox/readonly-type-handler.ts (2)
src/utils/typebox-codegen-utils.ts (1)
makeTypeCall(3-12)src/utils/typebox-call.ts (1)
getTypeBoxType(9-21)
🪛 LanguageTool
ARCHITECTURE.md
[grammar] ~27-~27: There might be a mistake here.
Context: ...arameters and proper constraint handling - Complex Types: Union and intersection ...
(QB_NEW_EN)
[grammar] ~28-~28: There might be a mistake here.
Context: ...bject structures, template literal types - Utility Types: Built-in support for Pi...
(QB_NEW_EN)
[grammar] ~29-~29: There might be a mistake here.
Context: ...only, and other TypeScript utility types - Advanced Features: Conditional types, ...
(QB_NEW_EN)
[grammar] ~42-~42: There might be a mistake here.
Context: ...ed TypeBox imports (including TSchema) 3. Output File Creation: Creates a new ou...
(QB_NEW_EN)
[grammar] ~143-~143: There might be a mistake here.
Context: ...lity Type**: Readonly<T> - Handled by - Registered as a type reference handler f...
(QB_NEW_EN)
[grammar] ~151-~151: There might be a mistake here.
Context: ...ly(innerType)` for array modifier syntax - Registered as a fallback handler to hand...
(QB_NEW_EN)
[grammar] ~214-~214: There might be a mistake here.
Context: ...matically detects type parameters using typeAlias.getTypeParameters() 2. Function Generation: Creates TypeBox f...
(QB_NEW_EN)
[grammar] ~215-~215: There might be a mistake here.
Context: ...liases with proper parameter constraints 3. TSchema Constraints: Applies TSchema...
(QB_NEW_EN)
[grammar] ~216-~216: There might be a mistake here.
Context: ...ype parameters for TypeBox compatibility 4. Static Type Generation: Generates corr...
(QB_NEW_EN)
[grammar] ~234-~234: There might be a mistake here.
Context: ...c parameters (e.g., ApiResponse<T, E>) - Nested Generic Types: Generic types th...
(QB_NEW_EN)
[grammar] ~235-~235: There might be a mistake here.
Context: ...types that reference other generic types - Utility Type Combinations: Complex com...
(QB_NEW_EN)
[grammar] ~236-~236: There might be a mistake here.
Context: ...mbinations**: Complex combinations like Partial<Readonly<Record<K, V>>> - Type Parameter Propagation: Proper han...
(QB_NEW_EN)
[grammar] ~299-~299: There might be a mistake here.
Context: ... standardized static type aliases using Static<ReturnType<typeof TypeName<T>>> - Architectural Consistency: Ensures bot...
(QB_NEW_EN)
🔇 Additional comments (6)
src/handlers/typebox/readonly-array-type-handler.ts (1)
5-11: Confirm operand constraint (arrays/tuples only).If TypeOperatorBaseHandler doesn’t restrict Readonly to array/tuple TypeOperatorNodes, add a guard to avoid mis-handling other constructs.
src/handlers/typebox/object/interface-type-handler.ts (1)
15-33: Returning raw TypeBox expressions for generics is fine—verify wrapping.Ensure GenericTypeUtils (parser layer) wraps these with the generic arrow function and Static<ReturnType<...>> consistently.
src/handlers/typebox/typebox-type-handlers.ts (1)
54-55: Good layering for Readonly forms.
Readonlymapped via typeReferenceHandlers.readonlyoperator handled by the new fallbackReadonlyArrayTypeHandler.
This avoids collisions and preserves fast-path lookups.Double-check that
ReadonlyArrayTypeHandler.canHandle(...)won’t matchReadonly<T>(TypeReference), only thereadonlyTypeOperator applied to arrays/tuples.Also applies to: 85-85, 92-93
src/index.ts (1)
81-86: Generic detection now includes type aliases—LGTM.Ensures
TSchemaimport appears when either interfaces or type aliases are generic.tests/handlers/typebox/readonly.test.ts (1)
46-60: Covers generic Readonly including TSchema import—nice.This aligns with the new generic codegen path.
src/handlers/typebox/readonly-type-handler.ts (1)
10-15: Good refactor: type-reference based Readonly handler is clear and correct.Validation + single-argument extraction +
Type.Readonly(...)is consistent with the new handler architecture.
| ### Generic Type Support | ||
|
|
||
| The codebase provides comprehensive support for both generic interfaces and generic type aliases, enabling complex type transformations and reusable type definitions. | ||
|
|
||
| #### Generic Type Aliases | ||
|
|
||
| The `TypeAliasParser` handles both regular and generic type aliases through specialized processing: | ||
|
|
||
| 1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()` | ||
| 2. **Function Generation**: Creates TypeBox functions for generic type aliases with proper parameter constraints | ||
| 3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility | ||
| 4. **Static Type Generation**: Generates corresponding TypeScript type aliases using `Static<ReturnType<typeof TypeName<T>>>` | ||
|
|
||
| #### Generic Interface Support | ||
|
|
||
| Generic interfaces are processed through the `InterfaceParser` using a consistent architectural pattern that mirrors the type alias flow: | ||
|
|
||
| 1. **Unified Generic Processing**: The interface parser now uses the same `GenericTypeUtils.createGenericArrowFunction` flow as type aliases for consistency | ||
| 2. **Raw Expression Handling**: The `InterfaceTypeHandler` returns raw TypeBox expressions for generic interfaces, allowing the parser to handle arrow function wrapping | ||
| 3. **Parameter Constraint Handling**: Converts TypeScript type parameter constraints to `TSchema` constraints using shared utilities | ||
| 4. **Function-Based Schema Generation**: Creates TypeBox schema functions that accept type parameters through the standardized generic arrow function pattern | ||
| 5. **Type Safety Preservation**: Maintains full TypeScript type safety through proper static type aliases using `Static<ReturnType<typeof TypeName<T>>>` | ||
| 6. **Architectural Consistency**: Both generic interfaces and type aliases now follow the same code generation pattern, improving maintainability and reducing duplication | ||
|
|
||
| #### Complex Generic Scenarios | ||
|
|
||
| The system supports advanced generic patterns including: | ||
|
|
||
| - **Multiple Type Parameters**: Functions with multiple generic parameters (e.g., `ApiResponse<T, E>`) | ||
| - **Nested Generic Types**: Generic types that reference other generic types | ||
| - **Utility Type Combinations**: Complex combinations like `Partial<Readonly<Record<K, V>>>` | ||
| - **Type Parameter Propagation**: Proper handling of type parameters across nested type references | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Doc reflects invalid TS pattern for generic static aliases. Update guidance.
Static<ReturnType<typeof TypeName<T>>> is not valid TS. Recommend not emitting generic static aliases; advise usage-site inference instead.
-1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()`
-2. **Function Generation**: Creates TypeBox functions for generic type aliases with proper parameter constraints
-3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility
-4. **Static Type Generation**: Generates corresponding TypeScript type aliases using `Static<ReturnType<typeof TypeName<T>>>`
+1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()`.
+2. **Function Generation**: Creates TypeBox factory functions for generic type aliases with proper parameter constraints.
+3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility.
+4. **Static Types (Generics)**: Do not emit generic static aliases due to TypeScript limitations with `typeof` on generic functions. Prefer usage-site inference:
+ `const S = TypeName(Type.String()); type S = Static<typeof S>;`.-1. **Unified Generic Processing**: The interface parser now uses the same `GenericTypeUtils.createGenericArrowFunction` flow as type aliases for consistency
+1. **Unified Generic Processing**: The interface parser now uses the same `GenericTypeUtils.createGenericArrowFunction` flow as type aliases for consistency.
-5. **Type Safety Preservation**: Maintains full TypeScript type safety through proper static type aliases using `Static<ReturnType<typeof TypeName<T>>>`
+5. **Type Safety Preservation**: Maintains type safety via factory functions; consumers derive statics from concrete instances (`Static<typeof Factory(...)>`).
-6. **Architectural Consistency**: Both generic interfaces and type aliases now follow the same code generation pattern, improving maintainability and reducing duplication
+6. **Architectural Consistency**: Both generic interfaces and type aliases now follow the same code generation pattern, improving maintainability and reducing duplication.-- **Multiple Type Parameters**: Functions with multiple generic parameters (e.g., `ApiResponse<T, E>`)
-- **Nested Generic Types**: Generic types that reference other generic types
-- **Utility Type Combinations**: Complex combinations like `Partial<Readonly<Record<K, V>>>`
-- **Type Parameter Propagation**: Proper handling of type parameters across nested type references
+- **Multiple Type Parameters**: Functions with multiple generic parameters (e.g., `ApiResponse<T, E>`).
+- **Nested Generic Types**: Generic types that reference other generic types.
+- **Utility Type Combinations**: Complex combinations, like `Partial<Readonly<Record<K, V>>>`.
+- **Type Parameter Propagation**: Proper handling of type parameters across nested type references.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ### Generic Type Support | |
| The codebase provides comprehensive support for both generic interfaces and generic type aliases, enabling complex type transformations and reusable type definitions. | |
| #### Generic Type Aliases | |
| The `TypeAliasParser` handles both regular and generic type aliases through specialized processing: | |
| 1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()` | |
| 2. **Function Generation**: Creates TypeBox functions for generic type aliases with proper parameter constraints | |
| 3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility | |
| 4. **Static Type Generation**: Generates corresponding TypeScript type aliases using `Static<ReturnType<typeof TypeName<T>>>` | |
| #### Generic Interface Support | |
| Generic interfaces are processed through the `InterfaceParser` using a consistent architectural pattern that mirrors the type alias flow: | |
| 1. **Unified Generic Processing**: The interface parser now uses the same `GenericTypeUtils.createGenericArrowFunction` flow as type aliases for consistency | |
| 2. **Raw Expression Handling**: The `InterfaceTypeHandler` returns raw TypeBox expressions for generic interfaces, allowing the parser to handle arrow function wrapping | |
| 3. **Parameter Constraint Handling**: Converts TypeScript type parameter constraints to `TSchema` constraints using shared utilities | |
| 4. **Function-Based Schema Generation**: Creates TypeBox schema functions that accept type parameters through the standardized generic arrow function pattern | |
| 5. **Type Safety Preservation**: Maintains full TypeScript type safety through proper static type aliases using `Static<ReturnType<typeof TypeName<T>>>` | |
| 6. **Architectural Consistency**: Both generic interfaces and type aliases now follow the same code generation pattern, improving maintainability and reducing duplication | |
| #### Complex Generic Scenarios | |
| The system supports advanced generic patterns including: | |
| - **Multiple Type Parameters**: Functions with multiple generic parameters (e.g., `ApiResponse<T, E>`) | |
| - **Nested Generic Types**: Generic types that reference other generic types | |
| - **Utility Type Combinations**: Complex combinations like `Partial<Readonly<Record<K, V>>>` | |
| - **Type Parameter Propagation**: Proper handling of type parameters across nested type references | |
| #### Generic Type Aliases | |
| The `TypeAliasParser` handles both regular and generic type aliases through specialized processing: | |
| 1. **Type Parameter Detection**: Automatically detects type parameters using `typeAlias.getTypeParameters()`. | |
| 2. **Function Generation**: Creates TypeBox factory functions for generic type aliases with proper parameter constraints. | |
| 3. **TSchema Constraints**: Applies `TSchema` constraints to all type parameters for TypeBox compatibility. | |
| 4. **Static Types (Generics)**: Do not emit generic static aliases due to TypeScript limitations with `typeof` on generic functions. Prefer usage-site inference: | |
| `const S = TypeName(Type.String()); type S = Static<typeof S>;`. | |
| #### Generic Interface Support | |
| Generic interfaces are processed through the `InterfaceParser` using a consistent architectural pattern that mirrors the type alias flow: | |
| 1. **Unified Generic Processing**: The interface parser now uses the same `GenericTypeUtils.createGenericArrowFunction` flow as type aliases for consistency. | |
| 2. **Raw Expression Handling**: The `InterfaceTypeHandler` returns raw TypeBox expressions for generic interfaces, allowing the parser to handle arrow function wrapping. | |
| 3. **Parameter Constraint Handling**: Converts TypeScript type parameter constraints to `TSchema` constraints using shared utilities. | |
| 4. **Function-Based Schema Generation**: Creates TypeBox schema functions that accept type parameters through the standardized generic arrow function pattern. | |
| 5. **Type Safety Preservation**: Maintains type safety via factory functions; consumers derive statics from concrete instances (`Static<typeof Factory(...)>`). | |
| 6. **Architectural Consistency**: Both generic interfaces and type aliases now follow the same code generation pattern, improving maintainability and reducing duplication. | |
| #### Complex Generic Scenarios | |
| The system supports advanced generic patterns including: | |
| - **Multiple Type Parameters**: Functions with multiple generic parameters (e.g., `ApiResponse<T, E>`). | |
| - **Nested Generic Types**: Generic types that reference other generic types. | |
| - **Utility Type Combinations**: Complex combinations, like `Partial<Readonly<Record<K, V>>>`. | |
| - **Type Parameter Propagation**: Proper handling of type parameters across nested type references. |
🧰 Tools
🪛 LanguageTool
[grammar] ~214-~214: There might be a mistake here.
Context: ...matically detects type parameters using typeAlias.getTypeParameters() 2. Function Generation: Creates TypeBox f...
(QB_NEW_EN)
[grammar] ~215-~215: There might be a mistake here.
Context: ...liases with proper parameter constraints 3. TSchema Constraints: Applies TSchema...
(QB_NEW_EN)
[grammar] ~216-~216: There might be a mistake here.
Context: ...ype parameters for TypeBox compatibility 4. Static Type Generation: Generates corr...
(QB_NEW_EN)
[grammar] ~234-~234: There might be a mistake here.
Context: ...c parameters (e.g., ApiResponse<T, E>) - Nested Generic Types: Generic types th...
(QB_NEW_EN)
[grammar] ~235-~235: There might be a mistake here.
Context: ...types that reference other generic types - Utility Type Combinations: Complex com...
(QB_NEW_EN)
[grammar] ~236-~236: There might be a mistake here.
Context: ...mbinations**: Complex combinations like Partial<Readonly<Record<K, V>>> - Type Parameter Propagation: Proper han...
(QB_NEW_EN)
🤖 Prompt for AI Agents
In ARCHITECTURE.md around lines 206-238, the doc incorrectly suggests emitting
generic static aliases using the invalid TypeScript pattern
`Static<ReturnType<typeof TypeName<T>>>`; remove that recommendation and update
the guidance to say we must NOT emit generic static aliases. Instead, explain
that generated schemas for generics should remain as runtime generic factory
functions (no generic `Static` aliases), and recommend consumers rely on
usage-site type inference or create concrete wrapper aliases/instantiations at
call sites (e.g., call the generic schema factory with concrete type parameters
and then apply Static to the resulting non-generic value), and update any
example text to reflect these valid alternatives.
| #### Generic Type Utilities | ||
|
|
||
| The <mcfile name="generic-type-utils.ts" path="src/utils/generic-type-utils.ts"></mcfile> module provides shared utilities for consistent generic type handling across parsers: | ||
|
|
||
| - **Generic Arrow Function Creation**: `createGenericArrowFunction` creates standardized arrow functions for generic types with proper type parameter constraints | ||
| - **Type Parameter Processing**: Converts TypeScript type parameters to TypeBox-compatible function parameters with `TSchema` constraints | ||
| - **Variable Statement Generation**: `addTypeBoxVariableStatement` creates consistent variable declarations for TypeBox schemas | ||
| - **Generic Type Alias Generation**: `addGenericTypeAlias` creates standardized static type aliases using `Static<ReturnType<typeof TypeName<T>>>` | ||
| - **Architectural Consistency**: Ensures both interface and type alias parsers follow the same generic type processing pattern | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Revise utility description: avoid promising generic static alias emission.
Align with the above guidance to prevent generating invalid TS.
-- **Generic Type Alias Generation**: `addGenericTypeAlias` creates standardized static type aliases using `Static<ReturnType<typeof TypeName<T>>>`
+- **Generic Static Alias Policy**: Skip emitting generic static aliases (the `typeof Name<T>` form is not valid TS); rely on usage-site inference (`Static<typeof Factory(...)>`).📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #### Generic Type Utilities | |
| The <mcfile name="generic-type-utils.ts" path="src/utils/generic-type-utils.ts"></mcfile> module provides shared utilities for consistent generic type handling across parsers: | |
| - **Generic Arrow Function Creation**: `createGenericArrowFunction` creates standardized arrow functions for generic types with proper type parameter constraints | |
| - **Type Parameter Processing**: Converts TypeScript type parameters to TypeBox-compatible function parameters with `TSchema` constraints | |
| - **Variable Statement Generation**: `addTypeBoxVariableStatement` creates consistent variable declarations for TypeBox schemas | |
| - **Generic Type Alias Generation**: `addGenericTypeAlias` creates standardized static type aliases using `Static<ReturnType<typeof TypeName<T>>>` | |
| - **Architectural Consistency**: Ensures both interface and type alias parsers follow the same generic type processing pattern | |
| #### Generic Type Utilities | |
| The <mcfile name="generic-type-utils.ts" path="src/utils/generic-type-utils.ts"></mcfile> module provides shared utilities for consistent generic type handling across parsers: | |
| - **Generic Arrow Function Creation**: `createGenericArrowFunction` creates standardized arrow functions for generic types with proper type parameter constraints | |
| - **Type Parameter Processing**: Converts TypeScript type parameters to TypeBox-compatible function parameters with `TSchema` constraints | |
| - **Variable Statement Generation**: `addTypeBoxVariableStatement` creates consistent variable declarations for TypeBox schemas | |
| - **Generic Static Alias Policy**: Skip emitting generic static aliases (the `typeof Name<T>` form is not valid TS); rely on usage-site inference (`Static<typeof Factory(...)>`). | |
| - **Architectural Consistency**: Ensures both interface and type alias parsers follow the same generic type processing pattern |
🧰 Tools
🪛 LanguageTool
[grammar] ~299-~299: There might be a mistake here.
Context: ... standardized static type aliases using Static<ReturnType<typeof TypeName<T>>> - Architectural Consistency: Ensures bot...
(QB_NEW_EN)
🤖 Prompt for AI Agents
In ARCHITECTURE.md around lines 292 to 301, the Generic Type Utilities section
incorrectly promises that addGenericTypeAlias "creates standardized static type
aliases using Static<ReturnType<typeof TypeName<T>>>", which implies the utility
emits generic static aliases (an invalid/unsupported output). Update the text to
remove the promise of emitting generic static aliases and instead describe the
actual behavior: that the module provides helpers for creating
TypeBox-compatible type parameters, standardized arrow function templates, and
variable statement helpers while explicitly noting that emitting generic
Static<...> aliases is not performed/supported; adjust the bullet for Generic
Type Alias Generation accordingly to state it standardizes type-alias patterns
where valid or documents limitations for generic static aliases.
| export const A = <T extends TSchema>(T: T) => Type.Object({ | ||
| a: T | ||
| }); | ||
| export type A<T extends TSchema> = Static<ReturnType<typeof A<T>>>; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Drop all invalid generic Static alias lines across tests.
Each export type X<...> = Static<ReturnType<typeof X<...>>> usage is not valid TS and will break consumers. Keep the factory functions; let users infer statics from concrete instances via Static<typeof X(...)>.
Example fix for the first case:
export const A = <T extends TSchema>(T: T) => Type.Object({
a: T
});
-
- export type A<T extends TSchema> = Static<ReturnType<typeof A<T>>>;Please apply the same removal to:
- Lines 58-65 (B alias),
- 89-96 (B alias in extended type case),
- 125-130 (LanguageRecord alias),
- 159-164 (UserResponse alias).
Run:
Also applies to: 58-65, 89-96, 125-130, 159-164
🏁 Script executed:
#!/usr/bin/env bash
rg -nP "export\s+type\s+\w+<[^>]+>\s*=\s*Static<\s*ReturnType<\s*typeof\s+\w+<" tests -g "!**/node_modules/**"Length of output: 2064
Drop all invalid generic Static<ReturnType<typeof…>> type aliases in typebox tests
Remove every export type X<…> = Static<ReturnType<typeof X<…>>>; line in these files—this pattern isn’t valid TS and breaks consumers (keep only the factory functions; users can infer statics via Static<typeof X(...)>):
- tests/handlers/typebox/readonly.test.ts (line 54)
- tests/handlers/typebox/interface-generics-runtime-binding.test.ts (lines 35, 66, 111)
- tests/handlers/typebox/interface-generics-consistency.test.ts (lines 46, 90)
- tests/handlers/typebox/generics.test.ts (lines 28, 58, 64, 95, 129, 159, 163)
🤖 Prompt for AI Agents
In tests/handlers/typebox/generics.test.ts around lines 24-29, the exported
generic type alias "export type A<T extends TSchema> = Static<ReturnType<typeof
A<T>>>;" is invalid TypeScript; remove that export type line (keep the factory
function export const A = <T extends TSchema>(T: T) => Type.Object({ a: T }) );
for any other similar occurrences in this file (lines 28, 58, 64, 95, 129, 159,
163) delete the "export type X<...> = Static<ReturnType<typeof X<...>>>;" lines
and, if any tests referenced those aliases, update them to use Static<typeof
X(...)> or infer the static type where needed.
| // Both should generate the same arrow function pattern | ||
| const expectedPattern = formatWithPrettier( | ||
| ` | ||
| export const Container = <T extends TSchema>(T: T) => Type.Object({ | ||
| value: T, | ||
| id: Type.String(), | ||
| }); | ||
| export type Container<T extends TSchema> = Static<ReturnType<typeof Container<T>>>; | ||
| `, | ||
| true, | ||
| true, | ||
| ) | ||
|
|
||
| expect(interfaceResult).toBe(expectedPattern) | ||
| expect(typeAliasResult).toBe(expectedPattern) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove invalid generic Static alias from expected pattern.
Same typeof Name<T> issue as above.
Apply:
export const Container = <T extends TSchema>(T: T) => Type.Object({
value: T,
id: Type.String(),
});
-
- export type Container<T extends TSchema> = Static<ReturnType<typeof Container<T>>>;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Both should generate the same arrow function pattern | |
| const expectedPattern = formatWithPrettier( | |
| ` | |
| export const Container = <T extends TSchema>(T: T) => Type.Object({ | |
| value: T, | |
| id: Type.String(), | |
| }); | |
| export type Container<T extends TSchema> = Static<ReturnType<typeof Container<T>>>; | |
| `, | |
| true, | |
| true, | |
| ) | |
| expect(interfaceResult).toBe(expectedPattern) | |
| expect(typeAliasResult).toBe(expectedPattern) | |
| }) | |
| // Both should generate the same arrow function pattern | |
| const expectedPattern = formatWithPrettier( | |
| ` | |
| export const Container = <T extends TSchema>(T: T) => Type.Object({ | |
| value: T, | |
| id: Type.String(), | |
| }); | |
| `, | |
| true, | |
| true, | |
| ) | |
| expect(interfaceResult).toBe(expectedPattern) | |
| expect(typeAliasResult).toBe(expectedPattern) | |
| }) |
🤖 Prompt for AI Agents
In tests/handlers/typebox/interface-generics-consistency.test.ts around lines 38
to 54, the expectedPattern includes an invalid generic usage in the Static alias
(using typeof Container<T>), so update the expected string to remove the generic
from the typeof expression; replace the line that defines the export type to use
Static<ReturnType<typeof Container>> (no <T> after Container) or otherwise
remove the invalid generic alias so the expectedPattern matches the generated
code.
| // Should generate using the same pattern as type aliases | ||
| expect(result).toBe( | ||
| formatWithPrettier( | ||
| ` | ||
| export const ApiResponse = <T extends TSchema, E extends TSchema>(T: T, E: E) => Type.Object({ | ||
| data: T, | ||
| error: E, | ||
| status: Type.Number(), | ||
| metadata: Type.Object({ | ||
| timestamp: Type.String(), | ||
| version: Type.Number(), | ||
| }), | ||
| }); | ||
| export type ApiResponse<T extends TSchema, E extends TSchema> = Static<ReturnType<typeof ApiResponse<T, E>>>; | ||
| `, | ||
| true, | ||
| true, | ||
| ), | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove invalid generic Static alias for ApiResponse as well.
export const ApiResponse = <T extends TSchema, E extends TSchema>(T: T, E: E) => Type.Object({
data: T,
error: E,
status: Type.Number(),
metadata: Type.Object({
timestamp: Type.String(),
version: Type.Number(),
}),
});
-
- export type ApiResponse<T extends TSchema, E extends TSchema> = Static<ReturnType<typeof ApiResponse<T, E>>>;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Should generate using the same pattern as type aliases | |
| expect(result).toBe( | |
| formatWithPrettier( | |
| ` | |
| export const ApiResponse = <T extends TSchema, E extends TSchema>(T: T, E: E) => Type.Object({ | |
| data: T, | |
| error: E, | |
| status: Type.Number(), | |
| metadata: Type.Object({ | |
| timestamp: Type.String(), | |
| version: Type.Number(), | |
| }), | |
| }); | |
| export type ApiResponse<T extends TSchema, E extends TSchema> = Static<ReturnType<typeof ApiResponse<T, E>>>; | |
| `, | |
| true, | |
| true, | |
| ), | |
| ) | |
| export const ApiResponse = <T extends TSchema, E extends TSchema>(T: T, E: E) => Type.Object({ | |
| data: T, | |
| error: E, | |
| status: Type.Number(), | |
| metadata: Type.Object({ | |
| timestamp: Type.String(), | |
| version: Type.Number(), | |
| }), | |
| }); |
🤖 Prompt for AI Agents
In tests/handlers/typebox/interface-generics-consistency.test.ts around lines 76
to 95, the expected snapshot contains an invalid generic Static alias for
ApiResponse; remove the generic type args from the Static/ReturnType usage.
Update the expected string so the type alias reads "export type ApiResponse<T
extends TSchema, E extends TSchema> = Static<ReturnType<typeof ApiResponse>>;"
(i.e. keep the generic parameters on the ApiResponse type but call
ReturnType<typeof ApiResponse> without <T, E>) and adjust formatting
accordingly.
| // The generated code should be an arrow function that takes type parameters | ||
| // and returns the TypeBox expression, not just the raw TypeBox expression | ||
| expect(result).toBe( | ||
| formatWithPrettier( | ||
| ` | ||
| export const Container = <T extends TSchema>(T: T) => Type.Object({ | ||
| value: T, | ||
| id: Type.String(), | ||
| }); | ||
| export type Container<T extends TSchema> = Static<ReturnType<typeof Container<T>>>; | ||
| `, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Invalid TypeScript in Static alias: ReturnType<typeof Container<T>> is not legal.
typeof Container<T> is not valid TS syntax; you cannot apply type arguments to a value typeof query. This pattern won't type-check in consumer projects even if string-equality tests pass.
Apply this diff to drop the invalid static alias from the expected output:
export const Container = <T extends TSchema>(T: T) => Type.Object({
value: T,
id: Type.String(),
});
-
- export type Container<T extends TSchema> = Static<ReturnType<typeof Container<T>>>;Run this quick scan to locate all occurrences of the invalid pattern across the repo:
🏁 Script executed:
#!/usr/bin/env bash
rg -nP "ReturnType<\s*typeof\s+\w+<" -g "!**/node_modules/**"Length of output: 2725
Remove invalid generic static aliases in generator, tests, and docs
The pattern Static<ReturnType<typeof X<T>>> isn’t valid TypeScript and appears in:
src/utils/generic-type-utils.ts(addGenericTypeAlias)- Tests under
tests/handlers/typebox/* - Documentation in
ARCHITECTURE.md
• In generic-type-utils.ts, stop emitting export type Name<T extends TSchema> = Static<ReturnType<typeof Name<T>>>
• Remove corresponding export type … = Static<ReturnType<typeof …<…>>> lines from all tests and update ARCHITECTURE.md accordingly
The changes in this commit add support for parsing and generating code for generic type aliases in the validation schema codegen tool.
The main changes are:
index.tsfile to check if any interfaces or type aliases have generic type parameters.parseGenericTypeAliasmethod in theTypeAliasParserclass to handle the parsing and code generation for generic type aliases.createGenericTypeAliasFunctionto generate the TypeBox function definition for the generic type alias.addGenericTypeAliasmethod to add the generic type alias declaration to the output file.These changes allow the validation schema codegen tool to properly handle and generate code for generic type aliases, which is an important feature for users who need to define complex schema types.