samchon / nestia

NestJS Helper Libraries + TypeScript OpenAPI generator
https://nestia.io/
MIT License
1.79k stars 93 forks source link

invalid type(_object) is generated in sdk. #293

Closed rojiwon123 closed 1 year ago

rojiwon123 commented 1 year ago

sdk doesn't generate Output type properly in specific case.

interface Pagination{
    page: number;
}

interface Try<T> {
    code: 1000;
    data: T;
}
interface IException {
    code: number;
    data: string;
}

type TryCatch<T,E extends IException> = Try<T> | E;
const exception1 = {code:4040, data:"test message"} as const;
const exception2 = {code:4030, data:"test message2"} as const;

// I think this is bug!
TryCatch<Pagination, typeof exception1> // this type doesn't generated properly.
// result: in sdk file, type Output = TryCatch<Pagination, __object>

TryCatch<Pagination, typeof exception1 | typeof exception2> // this type generated properly.
// result: in sdk file, type Output = TryCatch<Pagination, {code:4040, data:"test message"} |  {code:4030, data:"test message2"} >

and it's really my code.

// in contoller
  /**
   * 전체 상품 목록 조회
   *
   * @summary 상품 목록 조회 API
   * @tag products
   * @param page 페이지 정보 1이상의 정수, default 1
   * @returns 상품 목록
   * @throw 4002 유효하지 않은 query입니다.
   */
  @Get()
  async findMany(
    @Query('page') page?: string,
  ): Promise<
    TryCatch<
      PaginatedResponse<IProduct.Summary>,
      typeof Exception.INVALID_QUERY
    >
  > {
    const npage = Number(page ?? 1);
    if (isNaN(npage) || !typia.is<Page>({ page: npage }))
      return Exception.INVALID_QUERY;
    return ProductUsecase.findMany(npage);
  }

// in sdk file,
 export type Output = TryCatch<PaginatedResponse<IProduct.Summary>, __object>;
samchon commented 1 year ago

Use exact type instead of typeof statement.

rojiwon123 commented 1 year ago

this is second case (위와 다른 상황)

  @Get()
  async findMany(
    @Query('page') page?: string,
  ): Promise<
    PaginatedResponse<IProduct.Summary> | typeof Exception.INVALID_QUERY // union type
  > {
    const npage = Number(page ?? 1);
    if (isNaN(npage) || !typia.is<Page>({ page: npage }))
      return Exception.INVALID_QUERY;
    throw Error();
    //return ProductUsecase.findMany(npage);
  }

// in sdk file
    export type Output = { readonly code: "4002"; readonly data: "유효하지 않은 query입니다."; } | PaginatedResponse<Summary>;
// "PaginatedResponse<Summary>" doesn't imported. (import없이 타입명만 그대로 작성됩니다.)
rojiwon123 commented 1 year ago

but why typeof statement is not recommend?

samchon commented 1 year ago
  1. Your target instance of typeof statement is not exported
  2. TypeScript compiler does not know its exact name
kakasoo commented 1 year ago

@industriously This is very similar to my implementation. I will learn about this because I can also have this problem. If I find a solution, I will share it with you. Your problem with my understanding is that if a "E" that can be defined as a union type is specified as only one "typeof", it will appear as a "__object".

kakasoo commented 1 year ago

@samchon

Your target instance of typeof statement is not exported TypeScript compiler does not know its exact name

I can understand number 1, but it's hard to understand that there's no problem when there's more than two "typeof". If we can solve the problem with the type of keyword, I think we can solve many other problems. Isn't it similar, for example, when we don't define a type with a specific name, but just specify the type as an interface?

rojiwon123 commented 1 year ago

@industriously This is very similar to my implementation. I will learn about this because I can also have this problem. If I find a solution, I will share it with you. Your problem with my understanding is that if a "E" that can be defined as a union type is specified as only one "typeof", it will appear as a "__object".

@kakasoo 카카수님 블로그보고 적용한 사항이에용 :) "E"가 하나면 __object가 되고 union이면 원하는데로 정상작동합니다.

you're right.

kakasoo commented 1 year ago

@samchon Well, I don't know what it means if it's not an intersection or union type yet and at the same time aliasSymbol is undefined. I'm currently learning what I can figure out through TS compiler's "aliasSymbol". If you accept the commit I revised now, you can solve the problem mentioned in this issue. Can you check if the direction I'm going in is correct?

kakasoo commented 1 year ago

Successfully created the correct SDK for both Union type and otherwise.

image image
samchon commented 1 year ago

Decided to prohibit unnamed type using.