Typescript allows redundant keys when resolving promise with object

Viewed 71

Could you please help me to understand why Typescript does not throw an error here:

type Test = Promise<{a: number}>;
const test: Test = Promise.resolve({a: 1, something: 'wrong'}); // no error

but does here

type Test2 = {a: number};
const test2: Test2 = {a: 1, something: 'wrong'}; // error 2322, ok

And is there something I can do to make it throw the similar error with Promise?

Tried it on different versions on Typescript, including the latest one, with strict types. Tried with new Promise instead of Promise.resolve. Nothing helps. Take a look on Playground

Thank you in advance!

1 Answers

TypeScript only does excess property checks in very limited situations (direct assignment of object literals to typed variables, returning an object literal from a function; details here), because although from a type system perspective those extra properties are fine (they just mean the instance is of a subtype of the type which has more information), having them on an object literal you're assigning is typically a programmer mistake. It doesn't do that check otherwise because in the general case, it may well not be an error (just, again, a subtype).

You can trigger excess property checks on Promise.resolve by providing a type argument to it (playground link) (thanks jcalz!):

const test = Promise.resolve<{a: number}>({a: 1, something: 'wrong'});
//                                               ^^^^^^^^^^^^^^^^^^−− Argument of type '{ a: number; something: string; }' is not assignable to parameter of type '{ a: number; } | PromiseLike<{ a: number; }>'

In that, TypeScript will infer test's type as Promise<{a: number}> (e.g., your Test type).

You also get the check on async function returns (playground link):

type Test = Promise<{a: number}>;
async function asyncExample(a: number): Test {
    return {a, extra: true}; // Type '{ a: number; extra: boolean; }' is not assignable to type '{ a: number; }'
}

...so if you can use an async function rather than explicit promise syntax, you might be able to tighten up the checks.

Related