简体   繁体   中英

Object literal may only specify known properties, and 'data' does not exist in type 'PromiseLike<T>'

I have a method that makes a request to a server and, based on the URL, it might return completely differently shaped data.

Before this I was just casting the expected interface into the returned object:

    const data = Promise.resolve(makeSignedRequest(requestParameters));
    return data as Promise<AwesomeResponse>;

but today I came across this syntax, where I can tell the method explicitly what kind of data I'm expecting:

    const data = Promise.resolve(makeSignedRequest<AwesomeResponse>(requestParameters));
    return data;

Now. the makeSignedRequest may return types like, AwesomeResponse , GreatResponse , AmazingResponse but there is a common thing in all these. They all share the same structure - the structure of BaseResponse .

All my responses extend the BaseResponse , so we're cool there.

Having said all that, TypeScript is still complaining about the following code:

import https from "https";
export interface BaseResponse {
    meta: {};
    data: Array<{}>;
    error?: {
        statusCode: number | undefined;
        statusMessage: string | undefined;
    };
}

export const makeSignedRequest = <T>(url): Promise<T> => {
    return new Promise((resolve, reject) => {
        // create Request with event listeners
        const req = https.request(url, (res) => {
            res.on("end", () => {
                if (res.statusCode !== 200) {
                    resolve({
                        data: [],
                        meta: {},
                        error: {}
                    });
                }
            });
        });
    });
};

the resolve({data: [], gets heavily underlined by VS Code, because as I mentioned in the title,

Argument of type '{ data: never[]; meta: {}; error: { statusCode: number | undefined; statusMessage: string | undefined; }; }' is not assignable to parameter of type 'T | PromiseLike<T> | undefined'.
Object literal may only specify known properties, and 'data' does not exist in type 'PromiseLike<T>'.

What am I missing here?

You need a generic constraint :

export const makeSignedRequest = < T extends BaseResponse  > ...

and a type assertion:

      resolve({
        data: [],
        meta: {},
        error: {
          statusCode: res.statusCode,
          statusMessage: res.statusMessage,
        },
      } as T);

This code works for me in VSCode with TS 3.8.3

export interface BaseResponse {
    data: [];
    meta: {};
    error?: {
        statusCode: number | undefined;
        statusMessage: string | undefined;
    };
}

function makeSignedRequest<T extends BaseResponse>(): Promise<T> {
    return new Promise((resolve, reject) => {
        // create Request with event listener
        resolve({
            data: [],
            meta: {},
            error: {},
        } as T);
    });
}

You are saying that: your function return a generic type Promise, so resolve only accepts T as parameter. But {data: [], meta: {}, error: {}} is not T, as T can be anything (string, number...), so it won't compile. Your function does not make sense with generic type, it should return Promise<BaseReponse> , that's all. Return Promise<T> does not produce any benefit

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM