CRice
CRice

Reputation: 32276

Index signature missing in type: why is this an error?

Take the following typescript:

type Primitive = undefined | null | boolean | number | string;

// A POJO is just supposed to be your typical object, with nothing 
// fancy, but where we don't exactly know what's in it.
interface POJO {
    [key: string]: Primitive | POJO;
}

Okay, so the POJO is just supposed to represent some generic object, but a nice simple one. Might be something I'm going to JSON.stringify or whatever. Now here's the offending code:

// Some functions implemented elsewhere...
declare function post(path: string, data: POJO): Promise<Response>;
declare function getToken(): string;

type LinkOrMessage = {link: string} | {message: string};

function specialPost(path: string, data: LinkOrMessage): Promise<Response> {
    const body = {
        ...data,
        token: getToken(),
    };

    // Error: see below...
    return post(path, body);
}

The error is:

Argument of type '{ token: string; link: string; } | { token: string; message: string; }'
is not assignable to parameter of type 'POJO'.

Type '{ token: string; link: string; }'
is not assignable to type 'POJO'.

Index signature is missing in type '{ token: string; link: string; }'

Wat? Moreover, if we change the LinkOrMessage type so that it's not a union, e.g. simplify it to just {link: string}, the error goes away! Same if we simplify to just {message: string}. So clearly each type in the union is assignable to POJO, yet the union is itself not?

Can someone shed some light on this behavior?

Upvotes: 3

Views: 9322

Answers (1)

jcalz
jcalz

Reputation: 330571

Since TypeScript 2.0 there is such a thing as an implicit index signature which lets you assign certain objects of types without index signatures to variables of types with index signatures. But the rules for when to infer an implicit index signature are a little questionable (in that some people question them). In particular, there seems to be something going on with the interaction between implicit index signatures and the spread operator.

I think the good news for you may be that the particular issue you are seeing is probably a bug introduced in TypeScript v2.4 and fixed in TypeScript v2.6.1. The not-so-good news is that v2.6.1 isn't out yet; you can try to compile against typescript@next to see if it is cleared up.

Good luck!

Upvotes: 5

Related Questions