Skip to content
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

Simplest generic function doesn't work, because "too complex"? #165

Closed
valyagolev opened this issue Sep 2, 2023 · 2 comments
Closed

Simplest generic function doesn't work, because "too complex"? #165

valyagolev opened this issue Sep 2, 2023 · 2 comments
Labels
question Further information is requested

Comments

@valyagolev
Copy link

valyagolev commented Sep 2, 2023

"typescript": "5.2.2"
"json-schema-to-ts": "^2.9.2"

I was trying to come up with a way to describe GPT functions, along with the name and description:

export type GPTFunction = {
  name: string;
  description?: string;
  parameters: { type: "object" } & JSONSchema;
};

export type Return<T extends GPTFunction> = FromSchema<T["parameters"]>;

export const SetImprovedDescription = {
  name: "set_improved_description",
  description: "Set improved description",
  parameters: {
    type: "object",
    properties: {
      description: { type: "string" },
      explanation_for_changes: { type: "string" },
    },
    required: ["description"],
    additionalProperties: false,
  },
} as const satisfies GPTFunction;

But then this doesn't work:

function call_gpt<T extends GPTFunction>(
  schema: T,
  system: string,
  user: string
): null | Return<T> {
  return null;
}

const a = call_gpt(SetImprovedDescription, "system", "user");

It errors out with:

Type instantiation is excessively deep and possibly infinite.ts(2589)
Expression produces a union type that is too complex to represent.ts(2590)

Most weirdly, while it does error out, it actually still correctly infers the type!

Screenshot 2023-09-02 at 17 18 58

I also tried simplifying the function declaration. Avoiding my types (Return and GPTFunction), and replacing them with their applications directly doesn't change the error.

This works, but it's not what I need unfortunately:

export function call_gpt2<T extends JSONSchema>(
  schema: T,
  system: string,
  user: string
): null | FromSchema<T> {
  return null;
}

const b = call_gpt2(SetImprovedDescription["parameters"], "system", "user");

Another attempt that doesn't work, and it's actually quite a simple thing:

function make_gpt_caller<T extends JSONSchema>(
  name: string,
  description: string,
  // parameters: Narrow<T> // tried both ways
  parameters: T
): (system: string, user: string) => FromSchema<T> {
  return (system: string, user: string) => {
    return null as any;
  };
}

No custom types, very simple generic... still I get, even without ever calling this, for "return":

Type instantiation is excessively deep and possibly infinite.ts(2589)
Expression produces a union type that is too complex to represent.ts(2590)

What do I miss? Did I misconfigure something, or is there a different ways to use generics here?

@ThomasAribart
Copy link
Owner

ThomasAribart commented Dec 18, 2023

@valyagolev Hope I'm not answering too late.

I already had this issue in other libs. This is some TS internals dark magic that I don't understand anything about, but it will work if you use a second unconstrained generic like this:

export type GPTFunction = {
  name: string;
  description?: string;
  parameters: { type: "object" } & JSONSchema;
};

export type Return<T extends GPTFunction> = FromSchema<T["parameters"]>;

export const SetImprovedDescription = {
  name: "set_improved_description",
  description: "Set improved description",
  parameters: {
    type: "object",
    properties: {
      description: { type: "string" },
      explanation_for_changes: { type: "string" },
    },
    required: ["description"],
    additionalProperties: false,
  },
} as const satisfies GPTFunction;

// Will work !
function call_gpt<T extends GPTFunction, R = Return<T>>(
  schema: T,
  system: string,
  user: string,
): null | R {
  return null;
}

const a = call_gpt(SetImprovedDescription, "system", "user");

Will add a section in the FAQ about that!

@ThomasAribart ThomasAribart added the question Further information is requested label Dec 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants