In this particular scenario, there is no difference between the two since inference categorizes both fuzz
and buzz
as (foo: Foo) => Bar
. The distinction becomes apparent if you attempt to insert another if
condition prior to the final return statement, which yields a different outcome:
interface Foo { foo: number }
interface Bar { bar: Foo[] }
// type assertion
function buzz(foo: Foo) {
// This changes the return type of `buzz` to Bar | object
if (foo.foo > 10) return {};
return { bar: [] } as Bar;
}
// typing the function
function fuzz(foo: Foo): Bar {
// This results in a type error, as `fuzz` requires a return type of `Bar`
if (foo.foo > 10) return {};
return { bar: [] };
}
Effectively, in the first instance, adjustments are made within buzz
, whereas in the second, an error occurs within fuzz
.
The fundamental distinction lies in the intention: specifying Bar
as the return type implies that the output is defined and any implementation must adhere to this expected output. Conversely, using as Bar
indicates that while the current return is an object, it is anticipated to be a Bar
. Nonetheless, should this change, the return type will need to be updated accordingly.