In my current project, I encountered a scenario where a React callback led to a contrived example.
interface A {
a: string
b: string
}
interface B {
a: string
b: string
c: string
}
function foo(fn: (a: A) => void, a: A) {
fn(a)
}
function bar(arg: B): void {
console.log(arg.c)
}
foo(bar, {a: 'a', b: 'b'}) // Surprisingly, this works
This situation reveals that bar
can be passed as an argument to foo
, even though the number of fields in its first argument exceeds what is expected according to the type declaration. This means that users providing bar
as a callback may mistakenly assume they have access to a c
string
in their argument when they do not actually have it.
It is worth noting that there is some level of type checking on the arguments, as shown by the following failure case:
function baz(arg: string) { }
foo(baz, {a: 'a', b: 'b'}) // This fails as expected
The question arises about the underlying mechanism at play here and whether there is a way to define types more precisely to achieve a behavior closer to the desired outcome.