Skip to content
This repository has been archived by the owner on Jul 13, 2023. It is now read-only.

httpMethod no longer expects a string in TypeScript #331

Closed
shruggr opened this issue Jan 8, 2020 · 17 comments
Closed

httpMethod no longer expects a string in TypeScript #331

shruggr opened this issue Jan 8, 2020 · 17 comments
Assignees
Labels
api: cloudtasks Issues related to the googleapis/nodejs-tasks API. priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.

Comments

@shruggr
Copy link

shruggr commented Jan 8, 2020

In 1.7.0, when creating a new task, I get the following error. It works fine in 1.6.0

error TS2322: Type '{ httpRequest: { httpMethod: string; url: string; body: Buffer; headers: { "Content-Type": string; }; }; scheduleTime: { seconds: number; }; }' is not assignable to type 'ITask'.
  The types of 'httpRequest.httpMethod' are incompatible between these types.
    Type 'string' is not assignable to type 'HttpMethod'.

Environment details

  • OS: Windows 10
  • Node.js version: v12.0.0
  • npm version: 6.9.0
  • @google-cloud/tasks version: 1.7.0

Steps to reproduce

const client = new CloudTasksClient();
const task = {
    httpRequest: {
        httpMethod: 'POST',
        url: EVENT_URL,
        body: Buffer.from(JSON.stringify({a: 1})),
        headers: {
            "Content-Type": "application/json"
        }
    },
    scheduleTime: {
        seconds: delaySeconds + Date.now() / 1000
    }
};
await client.createTask({ parent: QUEUE_PATH, task });
@yoshi-automation yoshi-automation added the triage me I really want to be triaged. label Jan 9, 2020
@bcoe bcoe added type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns. priority: p2 Moderately-important priority. Fix may not be included in next release. labels Jan 9, 2020
@bcoe
Copy link
Contributor

bcoe commented Jan 9, 2020

@shruggr thanks for the bug report; @xiaozhenliu-gg5, @alexander-fenster looks like potentially a bug with the move to the microgenerator?

@alexander-fenster
Copy link
Contributor

alexander-fenster commented Jan 9, 2020

@shruggr Yeah, we're aware of this problem. If you had used JavaScript, the string would've worked just fine, but in TypeScript, you can't just assign a string to something that is not a string (but is a enum).

Right now, there are two ways to solve it:

  1. Use a proper enum:
import * as protos from '@google-cloud/tasks/build/protos/protos';

const task = {
  httpRequest: {
    httpMethod: protos.google.cloud.tasks.v2.HttpMethod.POST,
  . . .
};
  1. Alternatively, you can still use a string, just use the protobuf.js fromObject:
import * as protos from '@google-cloud/tasks/build/protos/protos';

const task = protos.google.cloud.tasks.v2.Task.fromObject({
  httpRequest: {
    httpMethod: 'POST',
  . . .
});

I have submitted an issue for the code generator we use, we'll figure out the best way to make it transparent, but until that time, feel free to use one of the above solutions.

@alexander-fenster
Copy link
Contributor

This should be fixed in v1.7.3. We updated the types to include all possible string values using keyof typeof google.cloud.tasks.v2.HttpMethod, this is the best we could do without breaking existing code.

@jacksontong
Copy link

I still have this issue in v1.9.0

@alexander-fenster
Copy link
Contributor

alexander-fenster commented Mar 26, 2020

@jacksontong All httpMethod fields accept strings in v1.9.0:

$ grep version node_modules/\@google-cloud/tasks/package.json 
  "version": "1.9.0"
$ grep httpMethod node_modules/\@google-cloud/tasks/build/protos/protos.d.ts 
                    /** HttpRequest httpMethod */
                    httpMethod?: (google.cloud.tasks.v2.HttpMethod|keyof typeof google.cloud.tasks.v2.HttpMethod|null);
                    /** HttpRequest httpMethod. */
                    public httpMethod: (google.cloud.tasks.v2.HttpMethod|keyof typeof google.cloud.tasks.v2.HttpMethod);
                    /** AppEngineHttpRequest httpMethod */
                    httpMethod?: (google.cloud.tasks.v2.HttpMethod|keyof typeof google.cloud.tasks.v2.HttpMethod|null);
                    /** AppEngineHttpRequest httpMethod. */
                    public httpMethod: (google.cloud.tasks.v2.HttpMethod|keyof typeof google.cloud.tasks.v2.HttpMethod);
                    /** AppEngineHttpRequest httpMethod */
                    httpMethod?: (google.cloud.tasks.v2beta2.HttpMethod|keyof typeof google.cloud.tasks.v2beta2.HttpMethod|null);
                    /** AppEngineHttpRequest httpMethod. */
                    public httpMethod: (google.cloud.tasks.v2beta2.HttpMethod|keyof typeof google.cloud.tasks.v2beta2.HttpMethod);
                    /** HttpRequest httpMethod */
                    httpMethod?: (google.cloud.tasks.v2beta3.HttpMethod|keyof typeof google.cloud.tasks.v2beta3.HttpMethod|null);
                    /** HttpRequest httpMethod. */
                    public httpMethod: (google.cloud.tasks.v2beta3.HttpMethod|keyof typeof google.cloud.tasks.v2beta3.HttpMethod);
                    /** AppEngineHttpRequest httpMethod */
                    httpMethod?: (google.cloud.tasks.v2beta3.HttpMethod|keyof typeof google.cloud.tasks.v2beta3.HttpMethod|null);
                    /** AppEngineHttpRequest httpMethod. */
                    public httpMethod: (google.cloud.tasks.v2beta3.HttpMethod|keyof typeof google.cloud.tasks.v2beta3.HttpMethod);

If you still see the error, could you please share your code here? Thank you!

@jacksontong
Copy link

@jketcham
Copy link

jketcham commented May 4, 2020

I ran into this issue and was able to just reference the POST type from protos to get around it, but in case this is helpful here is the error I was getting before when I was just using a string 'POST':

src/tasks.ts:52:30 - error TS2345: Argument of type '{ parent: string; task: { appEngineHttpRequest: { httpMethod: string; relativeUri: string; body: string; }; }; }' is not assignable to parameter of type 'ICreateTaskRequest'.
  The types of 'task.appEngineHttpRequest.httpMethod' are incompatible between these types.
    Type 'string' is not assignable to type '"GET" | "HEAD" | "POST" | "DELETE" | "PUT" | "OPTIONS" | "PATCH" | HttpMethod | "HTTP_METHOD_UNSPECIFIED" | null | undefined'.

52     return client.createTask(request);

With code:

const parent = ...;

const task = {
  appEngineHttpRequest: {
    httpMethod: 'POST',
    relativeUri: '/index',
    body: Buffer.from(JSON.stringify(indexRequest)).toString('base64'),
  },
};

const request = { parent, task };

return client.createTask(request);

I'm on version 2.0.0 of @google-cloud/tasks.

@ottob
Copy link

ottob commented Sep 10, 2020

I ran into the same issue today using v2.1.0.

My code (copied from the js sample):

const task = {
  httpRequest: {
    httpMethod: 'POST',
    url,
  },
}

const request = { parent, task }
const [response] = await client.createTask(request)

Error:

Argument of type '{ parent: string; task: { httpRequest: { httpMethod: string; url: string; body: string | null; }; scheduleTime: { seconds: number; }; }; }' is not assignable to parameter of type 'ICreateTaskRequest'.
  The types of 'task.httpRequest.httpMethod' are incompatible between these types.
    Type 'string' is not assignable to type '"POST" | HttpMethod | "HTTP_METHOD_UNSPECIFIED" | "GET" | "HEAD" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | null | undefined'.ts(2345)

Using this code worked for me:

import { CloudTasksClient, protos } from '@google-cloud/tasks'

const task = {
  httpRequest: {
    httpMethod: protos.google.cloud.tasks.v2.HttpMethod.POST,
    url,
  },
}

@alexander-fenster
Copy link
Contributor

alexander-fenster commented Sep 10, 2020

OK, I see the problem now. The auto-inferred type for task has httpRequest: string and even though the value you're going to assign matches the type, the type checker gets mad.

I guess you could make the sample work by writing const task = { ..... } as protos.google.cloud.tasks.v2.CreateTaskRequest; but that's ugly too. Thank you folks for reporting this, we'll think how to deal with this properly.

@bzuker
Copy link

bzuker commented May 10, 2021

I also ran into this issue recently, has this been fixed or does it need to be reopened? Maybe exposing the enum could be a possibility?

@rconjoe
Copy link

rconjoe commented Jun 11, 2021

We had the same issue in 2.3.2. @alexander-fenster's solution to use fromObject quelled tsc complaints but when running the function would return an error:
TypeError: this.constructor.toObject is not a function

What ended up working for us was explicitly typing the task object to be sent to client.createTask() using the Itask properties found in proto.google.cloud.tasks.v2beta3.Itask.

@tomhoad
Copy link

tomhoad commented Sep 16, 2021

Still an issue as of 2.4.2.

The basic 'Getting Started' won't work with TS without directly importing the protos and using the enum directly.

@Stf-F
Copy link

Stf-F commented Feb 15, 2022

Just bumped into this today with 2.5.0 and importing protos did do the trick. 👍

@MorenoMdz
Copy link

protos.google.cloud.tasks.v2.HttpMethod.POST

Why is this issue closed? It is not clear that we need to use protos.google.cloud.tasks.v2.HttpMethod.POST, the documentation should be more clear and/or simply accept a string ENUM.

@alexander-fenster
Copy link
Contributor

@MorenoMdz It should accept a string enum value. The type definition uses keyof typeof so strings should be accepted, and on protobufjs side, string enum values are also accepted. Does it not work for you? Please share your code :)

@MorenoMdz
Copy link

keyof

We are using version 3.0.0, this works:

    const task = {
      httpRequest: {
        httpMethod: protos.google.cloud.tasks.v2.HttpMethod.POST,
        url: functionUrl,
        oidcToken: {
          serviceAccountEmail,
          audience: new URL(functionUrl).origin
        },
        headers: {
          "Content-Type": "application/json",
          ...headers
        },
        body
      },
      scheduleTime: { seconds: targetTimeInSeconds }
    };

But httpMethod: "POST" does not.

image

@alexander-fenster
Copy link
Contributor

alexander-fenster commented Jul 14, 2022

This is not the library problem, but the problem with how TypeScript guesses the type of the httpRequest field. Since you have const task = { httpRequest: 'POST' }, TypeScript decides that the type of the task variable is { httpRequest: string }, which cannot be be used in the API request because it expects { httpRequest: 'POST' | 'GET' | ... }. We could've solved this by making the parameter accept any string instead of keyof typeof ..., but then we would've lost all compile time checks for the string enum values.

You can do the following to tell TypeScript compiler that the type of the task is ITask:

import {CloudTasksClient, protos} from '@google-cloud/tasks';

...

    const task: protos.google.cloud.tasks.v2.ITask = {
      appEngineHttpRequest: {
        httpMethod: 'POST',
        relativeUri: '/log_payload',
      },
    };

and then it will understand that httpRequest is of type 'POST' | 'GET' | ... and will happily pass it to the API.

Since our samples are in JavaScript and not in TypeScript, sometimes (in cases like this one) they cannot be easily copy-pasted to the TypeScript code. I took samples/quickstart.js and made it compile in TypeScript by adding type information here and there: gist

I hope that helps!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api: cloudtasks Issues related to the googleapis/nodejs-tasks API. priority: p2 Moderately-important priority. Fix may not be included in next release. type: bug Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Projects
None yet
Development

No branches or pull requests