class-transformer icon indicating copy to clipboard operation
class-transformer copied to clipboard

plainToClass assumes response is an array

Open NathanHazout opened this issue 8 years ago • 5 comments

Given the following code:

getProposal(id: string) : Promise<Proposal> {
    const url = `${this.proposalsUrl}/${id}`;
    var headers = new Headers();
    this._authService.createAuthorizationHeader(headers);
    var options = new RequestOptions({ headers: headers });
    return this.http.get(url, options)
        .toPromise()
        .then(response => plainToClass(Proposal, response.json()));
}

I get the typescript error:

[ts] Type 'Promise<Proposal[]>' is not assignable to type 'Promise<Proposal>'. Type 'Proposal[]' is not assignable to type 'Proposal'. Property 'id' is missing in type 'Proposal[]'.

How did it conclude that the response is an array??

NathanHazout avatar Oct 08 '17 10:10 NathanHazout

You are having this issue because Typescript does not know the type of response.json(). This is because plainToClass (and some other methods from class-transformer) has multiple signatures. From src/index.ts:

/**
 * Converts plain (literal) object to class (constructor) object. Also works with arrays.
 */
export function plainToClass<T, V extends Array<any>>(cls: ClassType<T>, plain: V, options?: ClassTransformOptions): T[];
export function plainToClass<T, V>(cls: ClassType<T>, plain: V, options?: ClassTransformOptions): T;
export function plainToClass<T, V>(cls: ClassType<T>, plain: V|V[], options?: ClassTransformOptions): T|T[] {
    return classTransformer.plainToClass(cls, plain as any, options);
}

Since Typescript cannot determine the appropriate signature, I assume it just picks the first one, hence why it's telling you that Proposal[] is expected.

To fix your problem, you simply need to explicitly declare the type of response.json() using as Proposal:

.then(response => plainToClass(Proposal, response.json() as Proposal));

And off you go :)

gempain avatar Oct 10 '17 14:10 gempain

While that works - it seems a bit redundant?

rightisleft avatar Mar 27 '18 19:03 rightisleft

Hi there, What about this issue?

davidquintard avatar Mar 11 '19 09:03 davidquintard

Hello, I'm interested in this as well! Thanks!

DimiTech avatar Apr 23 '19 22:04 DimiTech

To array:

plainToClass(Permission, <any[]>JSON.parse(response))

To single:

plainToClass(Permission, <any>JSON.parse(response))

^-- a little less redundant.

Edit: Just came here in 2024 and chose one of the higher in the thread (and slightly redundant) answers, not realizing I'd found a better way in 2019 :D

jasperblues avatar May 27 '19 05:05 jasperblues