When it comes to comparing values in TypeScript, structural equivalence is used instead of name equivalence. This principle also extends to functions, which are considered as values of type Function
.
This means that the function myFunc
does not necessarily have to strictly adhere to the IMyFunc
type when defined. However, the compiler will still enforce checks if you attempt to use the myFunc
function in an incorrect manner.
type IMyFunc<P, R> = (p: P) => R;
function doSomething<P, R>(func: IMyFunc<P, R>, params: P) {
console.log("Running the doSomething function...")
const value: R = func(params);
console.log("The value returned by func is " + value);
}
function myFunc(p: number): string {
return "Value of p is " + p;
}
doSomething<number, string>(myFunc, 42);
doSomething<string, string>(myFunc, "42");
The first call to doSomething
will pass successfully because the signature of myFunc
aligns with the IMyFunc<int, string>
type expected by the func
parameter of doSomething
.
However, the second call to doSomething
will fail since it requires a func
of type IMyFunc<string, string>
.
UPDATE
If you want the TypeScript compiler to verify that your myFunc
function definition conforms to a signature specified by an IMyFunc
type, you should define your function by binding it to a variable rather than using the traditional function syntax.
Instead of writing:
function myFunc(p: number): string {
return "Value of p is " + p;
}
You can opt for:
const myFunc: IMyFunc<int, string> = function (p) {
return "Value of p is " + p;
}
In case you prefer emulating the declaration behavior of traditional function definitions more closely, consider using the var
keyword instead of let
or const
. This will ensure effective variable hoisting:
var myFunc: IMyFunc<int, string> = function (p) {
return "Value of p is " + p;
}