Reputation: 7203
I'm trying to have a strict type check over a function (A) passed in parameter to another function. The returned value of A must be a Partial
of a given interface.
So considering the following interface:
interface IUser {
name: string;
age: number;
}
What I want is TypeScript throwing me an error if the return value of a function is not a Partial
of this interface
function check(f: () => Partial<IUser>) {
return f; // implementation of this function is pointless, only the type checking here interests me
}
When returning an object that contains none of the key of the interface, TS gives an error, that's expected.
But when there is a least one of the key of IUser
on the returned object, no more error, that's unexpected
check(() => ({ foo: 'bar' })); // GOOD - Type '{ foo: 'bar' }' has no properties in common with type 'Partial<IUser>'.
check(() => ({ foo: 'bar', name: 'Dar' })); // BAD - no error
I can't understand why TS is not throwing an error, because when trying to create an object of type Partial<IUser>
with an extra property, an error is thrown.
const o: Partial<IUser> = {
name: 'Dar',
foo: 'bar',
}; // Object literal may only specify known properties, and 'foo' does not exist in type 'Partial<IUser>'.
Is there a way to have TS throwing an error when using a callback like this?
NB: tests done with TypeScript 2.8.1
Upvotes: 3
Views: 1935
Reputation: 211
While I'm not sure I have an exact answer, I believe this is behavior that is inherent to TypeScript, not the way you've used Partials.
Partials are defined in the TypeScript spec as follows:
type Partial<T> = {
[P in keyof T]?: T[P];
}
As a sanity check, I rewrote your code using an explicit Weak Type (See breaking change in TypeScript 2.4) instead of a Partial, and I got the same result.
I was able to find this issue on the TypeScript repo: Function interface doesn't type check return value for extra keys. It looks like the type does not automatically get inferred from the check
signature. It looks like it has to do with the freshness of the object literal, and the issue is not resolved (as you can see from that issue discussion).
The good news is that it looks like there is a way to enforce it manually. To do so, you can include the following:
check((): Partial<IUser> => ({ foo: 'bar', name: 'Dar' }));
This will now create a similar error to the assignment at bottom: Object literal may only specify known properties, and 'foo' does not exist in type 'Partial<IUser>'
. You can see it in the playground here.
Upvotes: 2