It will compile because you're doing an assertion. You're basically saying "Trust me, TypeScript compiler, this is of the right type". That's circumventing the check altogether.
If your object satisfies the type, you don't need to do the assertion. Interfaces in TypeScript work by actually checking that the object satisfies the interface, not that it extends/implements the interface explicitly.
interface ResponseBody {
foo1: number;
foo2: string;
foo3: boolean;
}
function doSomething(value: ResponseBody) {
console.log("Ok");
}
And thus:
// This will work
doSomething({ foo1: 0, foo2: "zero", foo3: false });
// This will not work
// Argument of type '{ foo1: number; foo2: string; }' is not assignable to parameter of type 'ResponseBody'.
// Property 'foo3' is missing in type '{ foo1: number; foo2: string; }'.
doSomething({ foo1: 0, foo2: "zero" });
// This will not work
// Type 'number' is not assignable to type 'string'.
doSomething({ foo1: 0, foo2: 1, foo3: false });
// This will work
const r1: ResponseBody = { foo1: 4, foo2: "four", foo3: true };
// This will not work
// Type 'string' is not assignable to type 'number'.
const r2: ResponseBody = { foo1: '4' };
// This will not work
// Type '{ foo1: number; }' is not assignable to type 'ResponseBody'.
// Property 'foo2' is missing in type '{ foo1: number; }'.
const r3: ResponseBody = { foo1: 4 };
So the basic answer is: remove <Foo>
. You shouldn't need it.
Now, if the object you pass to doSomething
is coming from somewhere else and is of any
type, TypeScript cannot do the check. So it'll fail. Those are the cases where you'd need to add an assertion, to let TypeScript know that you know what you're doing. But that's because the object (and its fields) is not known at compile time, and therefore cannot be checked by TypeScript at all.