Parameters without types
The compiler infers a type from the value it sees in the code. So what value does it see for a function parameter with no default value? None. A parameter is like an empty jar put on the shelf in advance. What goes into it is decided by those who will call the function, and each of them may pour in something different.
Let's bring an ordinary JavaScript function over to TypeScript:
function add(a, b) { // ✗
return a + b;
}error TS7006: Parameter 'a' implicitly has an 'any' type.The message means: "the parameter a gets the type any without saying so". tsc reports the same error for b as well. In JavaScript this function works with anything: add(2, 3) gives 5, and add("2", 3) gives the string "23". TypeScript does not know what the author intended, and it won't guess.
Why calls don't give the type
It may seem that the compiler could look at how the function is called and infer the parameter's type from there. It does not, and there are reasons for that:
- a function is called from different places, even from other files, and each call may pass its own value;
- there may be no calls yet: a function is often written before it is used;
- a parameter's type is a contract written by the function's author, not by whoever calls it.
So a parameter without an annotation gets the type any—the same "anything goes" type you already saw on a variable without a value. With any there are no checks: a and b can be added to anything and have any method called on them, and the errors move back to run time.
The noImplicitAny check
Strict mode, which TypeScript 7 turns on by default, is made of several checks. One of them is noImplicitAny, "no implicit any": it forbids an any that appeared on its own, without your decision. This is the check that reports error TS7006.
The fix is to write the parameter types:
function add(a: number, b: number) {
return a + b;
}
console.log(add(2, 3)); // 5The result type need not be written here: from a + b of two numbers TypeScript infers number on its own. And the call add("2", 3) now gives error TS2345 before the program runs.
Where to write types
Interviewers often ask this: "When do you write a type, and when do you rely on inference?" The answer is built from what you already know:
- function parameters get a type—inference has nothing to read;
- so does a variable without an initial value;
- a variable with a value gets no annotation—its type is inferred from the value;
- the result type is inferred from
return, but you write it when you want to pin it: then an error in the function body shows right atreturn.
Common mistake
Writing the result type and deciding that the parameters are now clear:
function add(a, b): number { // ✗
return a + b;
}error TS7006: Parameter 'a' implicitly has an 'any' type.The result annotation tells nothing about the parameter types: TypeScript infers them neither from return nor from the calls. Every parameter needs its type: function add(a: number, b: number): number.
Key points
- A parameter without a default value has nothing to infer a type from: without an annotation it implicitly gets
any. - In strict mode the
noImplicitAnycheck turns such a parameter into errorTS7006. - With
anythere are no checks, and errors move to run time. - You write parameter types yourself, while the compiler infers the type of a variable with a value.