Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 7, 2025

Problem

The TypeScript code generator (goctl api ts) was producing incorrect code when API definitions contained inline/embedded structs. This resulted in three distinct issues:

  1. Incorrect argument counts: Generated functions had 4 arguments when only 2-3 were expected
  2. Non-existent type references: Code referenced Headers interfaces that were never generated
  3. Missing parameter interfaces: Structs with only embedded members didn't generate Params interfaces

Example

Given this API definition:

type PaginationReq {
    PageNum  int `form:"pageNum"`
    PageSize int `form:"pageSize"`
}

type GetListBadReq {
    Sth string `form:"sth"`
    PaginationReq  // embedded struct with form tags
}

type GetListBad2Req {
    PaginationReq  // only embedded struct
}

service test-api {
    @handler getListBad
    get /getListBad (GetListBadReq)
    
    @handler getListBad2
    get /getListBad2 (GetListBad2Req)
}

Before this fix, the generator produced:

// ERROR: Expected 2-3 arguments, but got 4
export function getListBad(params, req, headers) {
    return webapi.get(`/getListBad`, params, req, headers)
}

// ERROR: 'GetListBad2ReqHeaders' has no exported member
export function getListBad2(req, headers: GetListBad2ReqHeaders) {
    return webapi.get(`/getListBad2`, req, headers)
}

After this fix:

export function getListBad(params: components.GetListBadReqParams) {
    return webapi.get(`/getListBad`, params)
}

export function getListBad2(params: components.GetListBad2ReqParams) {
    return webapi.get(`/getListBad2`, params)
}

Root Cause

The generator used IsBodyMember() and IsTagMember() methods which return true for all inline/embedded members, regardless of whether they actually contain json/form/header/path tags. This caused:

  • Inline structs with form tags to be incorrectly treated as request bodies
  • Empty Headers interfaces to be generated when embedded structs had no header tags
  • Incorrect detection of whether params/body/headers should be generated

Solution

Implemented three recursive helper functions that properly distinguish between inline struct markers and actual tag presence:

  • hasActualTagMembers(tp, tagKey) - Recursively checks if a type actually has members with the specified tag (form/header/path)
  • hasActualBodyMembers(tp) - Recursively checks if a type actually has body members (json tags)
  • hasActualNonBodyMembers(tp) - Recursively checks if a type actually has non-body members (form/header/path tags)

These functions traverse embedded structs recursively to find actual tagged members, rather than stopping at the inline marker.

Changes

Modified Files

  • tools/goctl/api/tsgen/util.go

    • Added three recursive helper functions
    • Updated genParamsTypesIfNeed() to use hasActualNonBodyMembers() and hasActualTagMembers()
  • tools/goctl/api/tsgen/genpacket.go

    • Updated hasRequestBody() to use hasActualBodyMembers()
    • Updated hasRequestHeader() and hasRequestPath() to use hasActualTagMembers()
    • Updated pathHasParams() to use hasActualNonBodyMembers()

Test Coverage

  • Added comprehensive unit tests for all three helper functions covering empty structs, direct members, inline members, and mixed scenarios
  • Added end-to-end integration test using the exact API definition from the bug report
  • All existing tests pass, including race detector tests

Verification

The generated TypeScript code now:

  • ✅ Has correct function signatures with proper argument counts
  • ✅ Properly flattens embedded struct fields into Params interfaces
  • ✅ Only generates Headers interfaces when actual header tags exist
  • ✅ Compiles without TypeScript errors

Fixes #4344

Original prompt

This section details on the original issue you should resolve

<issue_title>[API TS Generator]Some codes generated by ts code generator of goctl are incorrect</issue_title>
<issue_description>Describe the bug
Some codes generated by ts code generator of goctl are incorrect

To Reproduce
Steps to reproduce the behavior, if applicable:

goctl api ts --api .\test.api --dir .\js

The api file is as follows

syntax = "v1"

info (
title:   "Test ts generator"
desc:    "Some codes generated by ts code generator of goctl are incorrect"
author:  "HKB"
date:    "2025 年 8 月 22 日"
version: "v1"
)

// common pagination request
type PaginationReq {
PageNum  int `form:"pageNum"`
PageSize int `form:"pageSize"`
}

// base response
type BaseResp {
Code int64  `json:"code"`
Msg  string `json:"msg"`
}

// common req
type GetListCommonReq {
Sth      string `form:"sth"`
PageNum  int    `form:"pageNum"`
PageSize int    `form:"pageSize"`
}

// bad req to ts
type GetListBadReq {
Sth string `form:"sth"`
PaginationReq
}

// bad req to ts 2
type GetListBad2Req {
PaginationReq
}

// GetListResp
type GetListResp {
BaseResp
}

service test-api {
@doc "common req"
@handler getListCommon
get /getListCommon (GetListCommonReq) returns (GetListResp)

@doc "bad req"
@handler getListBad
get /getListBad (GetListBadReq) returns (GetListResp)

@doc "bad req 2"
@handler getListBad2
get /getListBad2 (GetListBad2Req) returns (GetListResp)

@doc "no req"
@handler getListNoReq
get /getListNoReq returns (GetListResp)
}   
  1. The error is

In generated file 'test.ts'

Expected 2-3 arguments, but got 4.  [Ln 12, Col 72]
'"******/testComponents"' has no exported member named 'GetListBad2ReqHeaders'. Did you mean 'GetListBadReqHeaders'?  [Ln 20, Col 81]
Expected 2-3 arguments, but got 1. [Ln 36, Col 16]

Expected behavior
The generated code should not have any errors.

Screenshots
If applicable, add screenshots to help explain your problem.

Environments (please complete the following information):

  • OS: Windows 11
  • go-zero version 1.9.0
  • goctl version 1.8.5 windows/amd64

More description
Add any other context about the problem here.
</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #5109

💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes three critical issues with the TypeScript code generator for go-zero API definitions when handling inline/embedded structs. The fixes ensure proper TypeScript parameter generation and interface creation for embedded structs with different tag types.

Key Changes

  • Added three new helper functions to recursively check for actual tag members in embedded structs
  • Modified the TypeScript generation logic to use these helpers instead of surface-level member checks
  • Added comprehensive test coverage for all new helper functions and end-to-end integration testing

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
tools/goctl/api/tsgen/util.go Added three recursive helper functions for checking actual tag members in embedded structs
tools/goctl/api/tsgen/genpacket.go Updated generation logic to use new helper functions for accurate parameter determination
tools/goctl/api/tsgen/util_test.go Added comprehensive unit tests for all three new helper functions
tools/goctl/api/tsgen/gen_test.go Added end-to-end integration test for inline struct handling scenarios
Copilot AI changed the title [WIP] Fix incorrect TypeScript code generated by goctl Oct 7, 2025
Copilot AI requested a review from kevwan October 7, 2025 03:38
Copilot finished work on behalf of kevwan October 7, 2025 03:38
Copilot AI and others added 3 commits October 25, 2025 20:11
- Add hasActualTagMembers helper to recursively check for actual tag members
- Add hasActualBodyMembers helper to recursively check for actual body members
- Add hasActualNonBodyMembers helper to recursively check for actual non-body members
- Update genParamsTypesIfNeed to use hasActualNonBodyMembers and hasActualTagMembers
- Update hasRequestBody, hasRequestHeader, hasRequestPath, and pathHasParams to use new helpers
- Add comprehensive test coverage for new helper functions

Co-authored-by: kevwan <1918356+kevwan@users.noreply.github.com>
- Add TestGenWithInlineStructs to verify end-to-end generation
- Test verifies correct parameter generation, flattening of inline structs
- Test verifies no incorrect Headers interfaces are generated
- Test verifies correct argument counts in function calls

Co-authored-by: kevwan <1918356+kevwan@users.noreply.github.com>
Co-authored-by: kevwan <1918356+kevwan@users.noreply.github.com>
@kevwan kevwan force-pushed the copilot/fix-incorrect-ts-code-generation branch from 104fa70 to 02191e0 Compare October 25, 2025 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants