ℹ️ Skipped - page is already crawled
| Filter | Status | Condition | Details |
|---|---|---|---|
| HTTP status | PASS | download_http_code = 200 | HTTP 200 |
| Age cutoff | PASS | download_stamp > now() - 6 MONTH | 0.2 months ago |
| History drop | PASS | isNull(history_drop_reason) | No drop reason |
| Spam/ban | PASS | fh_dont_index != 1 AND ml_spam_score = 0 | ml_spam_score=0 |
| Canonical | FAIL | meta_canonical IS NULL OR = '' OR = src_unparsed | org,typescriptlang!www,/docs/handbook/2/functions.html s443 |
| Property | Value |
|---|---|
| URL | https://www.typescriptlang.org/docs/handbook/functions.html |
| Last Crawled | 2026-04-15 20:54:25 (6 days ago) |
| First Indexed | 2016-04-04 10:56:00 (10 years ago) |
| HTTP Status Code | 200 |
| Meta Title | TypeScript: Handbook - Functions |
| Meta Description | How to add types to a function |
| Meta Canonical | org,typescriptlang!www,/docs/handbook/2/functions.html s443 |
| Boilerpipe Text | Functions are the fundamental building block of any application in JavaScript.
They’re how you build up layers of abstraction, mimicking classes, information hiding, and modules.
In TypeScript, while there are classes, namespaces, and modules, functions still play the key role in describing how to
do
things.
TypeScript also adds some new capabilities to the standard JavaScript functions to make them easier to work with.
Functions
To begin, just as in JavaScript, TypeScript functions can be created both as a named function or as an anonymous function.
This allows you to choose the most appropriate approach for your application, whether you’re building a list of functions in an API or a one-off function to hand off to another function.
To quickly recap what these two approaches look like in JavaScript:
ts
// Named function
function
add
(
x
,
y
) {
return
x
+
y
;
}
// Anonymous function
let
myAdd
=
function
(
x
,
y
) {
return
x
+
y
;
};
Try
Just as in JavaScript, functions can refer to variables outside of the function body.
When they do so, they’re said to
capture
these variables.
While understanding how this works (and the trade-offs when using this technique) is outside of the scope of this article, having a firm understanding how this mechanic works is an important piece of working with JavaScript and TypeScript.
ts
let
z
=
100
;
function
addToZ
(
x
,
y
) {
return
x
+
y
+
z
;
}
Try
Function Types
Typing the function
Let’s add types to our simple examples from earlier:
ts
function
add
(
x
:
number
,
y
:
number
):
number
{
return
x
+
y
;
}
let
myAdd
=
function
(
x
:
number
,
y
:
number
):
number
{
return
x
+
y
;
};
Try
We can add types to each of the parameters and then to the function itself to add a return type.
TypeScript can figure the return type out by looking at the return statements, so we can also optionally leave this off in many cases.
Writing the function type
Now that we’ve typed the function, let’s write the full type of the function out by looking at each piece of the function type.
ts
let
myAdd
: (
x
:
number
,
y
:
number
)
=>
number
=
function
(
x
:
number
,
y
:
number
):
number
{
return
x
+
y
;
};
Try
A function’s type has the same two parts: the type of the arguments and the return type.
When writing out the whole function type, both parts are required.
We write out the parameter types just like a parameter list, giving each parameter a name and a type.
This name is just to help with readability.
We could have instead written:
ts
let
myAdd
: (
baseValue
:
number
,
increment
:
number
)
=>
number
=
function
(
x
:
number
,
y
:
number
):
number
{
return
x
+
y
;
};
Try
As long as the parameter types line up, it’s considered a valid type for the function, regardless of the names you give the parameters in the function type.
The second part is the return type.
We make it clear which is the return type by using an arrow (
=>
) between the parameters and the return type.
As mentioned before, this is a required part of the function type, so if the function doesn’t return a value, you would use
void
instead of leaving it off.
Of note, only the parameters and the return type make up the function type.
Captured variables are not reflected in the type.
In effect, captured variables are part of the “hidden state” of any function and do not make up its API.
Inferring the types
In playing with the example, you may notice that the TypeScript compiler can figure out the type even if you only have types on one side of the equation:
ts
// The parameters 'x' and 'y' have the type number
let
myAdd
=
function
(
x
:
number
,
y
:
number
):
number
{
return
x
+
y
;
};
// myAdd has the full function type
let
myAdd2
: (
baseValue
:
number
,
increment
:
number
)
=>
number
=
function
(
x
,
y
) {
return
x
+
y
;
};
Try
This is called “contextual typing”, a form of type inference.
This helps cut down on the amount of effort to keep your program typed.
Optional and Default Parameters
In TypeScript, every parameter is assumed to be required by the function.
This doesn’t mean that it can’t be given
null
or
undefined
, but rather, when the function is called, the compiler will check that the user has provided a value for each parameter.
The compiler also assumes that these parameters are the only parameters that will be passed to the function.
In short, the number of arguments given to a function has to match the number of parameters the function expects.
ts
function
buildName
(
firstName
:
string
,
lastName
:
string
) {
return
firstName
+
" "
+
lastName
;
}
let
result1
=
buildName
(
"Bob"
);
// error, too few parameters
Expected 2 arguments, but got 1.
2554
Expected 2 arguments, but got 1.
let
result2
=
buildName
(
"Bob"
,
"Adams"
,
"Sr."
);
// error, too many parameters
Expected 2 arguments, but got 3.
2554
Expected 2 arguments, but got 3.
let
result3
=
buildName
(
"Bob"
,
"Adams"
);
// ah, just right
Try
In JavaScript, every parameter is optional, and users may leave them off as they see fit.
When they do, their value is
undefined
.
We can get this functionality in TypeScript by adding a
?
to the end of parameters we want to be optional.
For example, let’s say we want the last name parameter from above to be optional:
ts
function
buildName
(
firstName
:
string
,
lastName
?:
string
) {
if
(
lastName
)
return
firstName
+
" "
+
lastName
;
else
return
firstName
;
}
let
result1
=
buildName
(
"Bob"
);
// works correctly now
let
result2
=
buildName
(
"Bob"
,
"Adams"
,
"Sr."
);
// error, too many parameters
Expected 1-2 arguments, but got 3.
2554
Expected 1-2 arguments, but got 3.
let
result3
=
buildName
(
"Bob"
,
"Adams"
);
// ah, just right
Try
Any optional parameters must follow required parameters.
Had we wanted to make the first name optional, rather than the last name, we would need to change the order of parameters in the function, putting the first name last in the list.
In TypeScript, we can also set a value that a parameter will be assigned if the user does not provide one, or if the user passes
undefined
in its place.
These are called default-initialized parameters.
Let’s take the previous example and default the last name to
"Smith"
.
ts
function
buildName
(
firstName
:
string
,
lastName
=
"Smith"
) {
return
firstName
+
" "
+
lastName
;
}
let
result1
=
buildName
(
"Bob"
);
// works correctly now, returns "Bob Smith"
let
result2
=
buildName
(
"Bob"
,
undefined
);
// still works, also returns "Bob Smith"
let
result3
=
buildName
(
"Bob"
,
"Adams"
,
"Sr."
);
// error, too many parameters
Expected 1-2 arguments, but got 3.
2554
Expected 1-2 arguments, but got 3.
let
result4
=
buildName
(
"Bob"
,
"Adams"
);
// ah, just right
Try
Default-initialized parameters that come after all required parameters are treated as optional, and just like optional parameters, can be omitted when calling their respective function.
This means optional parameters and trailing default parameters will share commonality in their types, so both
ts
function
buildName
(
firstName
:
string
,
lastName
?:
string
) {
// ...
}
and
ts
function
buildName
(
firstName
:
string
,
lastName
=
"Smith"
) {
// ...
}
share the same type
(firstName: string, lastName?: string) => string
.
The default value of
lastName
disappears in the type, only leaving behind the fact that the parameter is optional.
Unlike plain optional parameters, default-initialized parameters don’t
need
to occur after required parameters.
If a default-initialized parameter comes before a required parameter, users need to explicitly pass
undefined
to get the default initialized value.
For example, we could write our last example with only a default initializer on
firstName
:
ts
function
buildName
(
firstName
=
"Will"
,
lastName
:
string
) {
return
firstName
+
" "
+
lastName
;
}
let
result1
=
buildName
(
"Bob"
);
// error, too few parameters
Expected 2 arguments, but got 1.
2554
Expected 2 arguments, but got 1.
let
result2
=
buildName
(
"Bob"
,
"Adams"
,
"Sr."
);
// error, too many parameters
Expected 2 arguments, but got 3.
2554
Expected 2 arguments, but got 3.
let
result3
=
buildName
(
"Bob"
,
"Adams"
);
// okay and returns "Bob Adams"
let
result4
=
buildName
(
undefined
,
"Adams"
);
// okay and returns "Will Adams"
Try
Rest Parameters
Required, optional, and default parameters all have one thing in common: they talk about one parameter at a time.
Sometimes, you want to work with multiple parameters as a group, or you may not know how many parameters a function will ultimately take.
In JavaScript, you can work with the arguments directly using the
arguments
variable that is visible inside every function body.
In TypeScript, you can gather these arguments together into a variable:
ts
function
buildName
(
firstName
:
string
, ...
restOfName
:
string
[]) {
return
firstName
+
" "
+
restOfName
.
join
(
" "
);
}
// employeeName will be "Joseph Samuel Lucas MacKinzie"
let
employeeName
=
buildName
(
"Joseph"
,
"Samuel"
,
"Lucas"
,
"MacKinzie"
);
Try
Rest parameters
are treated as a boundless number of optional parameters.
When passing arguments for a rest parameter, you can use as many as you want; you can even pass none.
The compiler will build an array of the arguments passed in with the name given after the ellipsis (
...
), allowing you to use it in your function.
The ellipsis is also used in the type of the function with rest parameters:
ts
function
buildName
(
firstName
:
string
, ...
restOfName
:
string
[]) {
return
firstName
+
" "
+
restOfName
.
join
(
" "
);
}
let
buildNameFun
: (
fname
:
string
, ...
rest
:
string
[])
=>
string
=
buildName
;
Try
this
Learning how to use
this
in JavaScript is something of a rite of passage.
Since TypeScript is a superset of JavaScript, TypeScript developers also need to learn how to use
this
and how to spot when it’s not being used correctly.
Fortunately, TypeScript lets you catch incorrect uses of
this
with a couple of techniques.
If you need to learn how
this
works in JavaScript, though, first read Yehuda Katz’s
Understanding JavaScript Function Invocation and “this”
.
Yehuda’s article explains the inner workings of
this
very well, so we’ll just cover the basics here.
this
and arrow functions
In JavaScript,
this
is a variable that’s set when a function is called.
This makes it a very powerful and flexible feature, but it comes at the cost of always having to know about the context that a function is executing in.
This is notoriously confusing, especially when returning a function or passing a function as an argument.
Let’s look at an example:
ts
let
deck
= {
suits
:
[
"hearts"
,
"spades"
,
"clubs"
,
"diamonds"
],
cards
:
Array
(
52
),
createCardPicker
:
function
() {
return
function
() {
let
pickedCard
=
Math
.
floor
(
Math
.
random
() *
52
);
let
pickedSuit
=
Math
.
floor
(
pickedCard
/
13
);
return
{
suit
:
this
.
suits
[
pickedSuit
],
card
:
pickedCard
%
13
};
};
},
};
let
cardPicker
=
deck
.
createCardPicker
();
let
pickedCard
=
cardPicker
();
alert
(
"card: "
+
pickedCard
.
card
+
" of "
+
pickedCard
.
suit
);
Try
Notice that
createCardPicker
is a function that itself returns a function.
If we tried to run the example, we would get an error instead of the expected alert box.
This is because the
this
being used in the function created by
createCardPicker
will be set to
window
instead of our
deck
object.
That’s because we call
cardPicker()
on its own.
A top-level non-method syntax call like this will use
window
for
this
.
(Note: under strict mode,
this
will be
undefined
rather than
window
).
We can fix this by making sure the function is bound to the correct
this
before we return the function to be used later.
This way, regardless of how it’s later used, it will still be able to see the original
deck
object.
To do this, we change the function expression to use the ECMAScript 6 arrow syntax.
Arrow functions capture the
this
where the function is created rather than where it is invoked:
ts
let
deck
= {
suits
:
[
"hearts"
,
"spades"
,
"clubs"
,
"diamonds"
],
cards
:
Array
(
52
),
createCardPicker
:
function
() {
// NOTE: the line below is now an arrow function, allowing us to capture 'this' right here
return
()
=>
{
let
pickedCard
=
Math
.
floor
(
Math
.
random
() *
52
);
let
pickedSuit
=
Math
.
floor
(
pickedCard
/
13
);
return
{
suit
:
this
.
suits
[
pickedSuit
],
card
:
pickedCard
%
13
};
};
},
};
let
cardPicker
=
deck
.
createCardPicker
();
let
pickedCard
=
cardPicker
();
alert
(
"card: "
+
pickedCard
.
card
+
" of "
+
pickedCard
.
suit
);
Try
Even better, TypeScript will warn you when you make this mistake if you pass the
noImplicitThis
flag to the compiler.
It will point out that
this
in
this.suits[pickedSuit]
is of type
any
.
this
parameters
Unfortunately, the type of
this.suits[pickedSuit]
is still
any
.
That’s because
this
comes from the function expression inside the object literal.
To fix this, you can provide an explicit
this
parameter.
this
parameters are fake parameters that come first in the parameter list of a function:
ts
function
f
(
this
:
void
) {
// make sure `this` is unusable in this standalone function
}
Let’s add a couple of interfaces to our example above,
Card
and
Deck
, to make the types clearer and easier to reuse:
ts
interface
Card
{
suit
:
string
;
card
:
number
;
}
interface
Deck
{
suits
:
string
[];
cards
:
number
[];
createCardPicker
(
this
:
Deck
): ()
=>
Card
;
}
let
deck
:
Deck
= {
suits
:
[
"hearts"
,
"spades"
,
"clubs"
,
"diamonds"
],
cards
:
Array
(
52
),
// NOTE: The function now explicitly specifies that its callee must be of type Deck
createCardPicker
:
function
(
this
:
Deck
) {
return
()
=>
{
let
pickedCard
=
Math
.
floor
(
Math
.
random
() *
52
);
let
pickedSuit
=
Math
.
floor
(
pickedCard
/
13
);
return
{
suit
:
this
.
suits
[
pickedSuit
],
card
:
pickedCard
%
13
};
};
},
};
let
cardPicker
=
deck
.
createCardPicker
();
let
pickedCard
=
cardPicker
();
alert
(
"card: "
+
pickedCard
.
card
+
" of "
+
pickedCard
.
suit
);
Try
Now TypeScript knows that
createCardPicker
expects to be called on a
Deck
object.
That means that
this
is of type
Deck
now, not
any
, so
noImplicitThis
will not cause any errors.
this
parameters in callbacks
You can also run into errors with
this
in callbacks, when you pass functions to a library that will later call them.
Because the library that calls your callback will call it like a normal function,
this
will be
undefined
.
With some work you can use
this
parameters to prevent errors with callbacks too.
First, the library author needs to annotate the callback type with
this
:
ts
interface
UIElement
{
addClickListener
(
onclick
: (
this
:
void
,
e
:
Event
)
=>
void
):
void
;
}
Try
this: void
means that
addClickListener
expects
onclick
to be a function that does not require a
this
type.
Second, annotate your calling code with
this
:
ts
class
Handler
{
info
:
string
;
onClickBad
(
this
:
Handler
,
e
:
Event
) {
// oops, used `this` here. using this callback would crash at runtime
this
.
info
=
e
.
message
;
}
}
let
h
=
new
Handler
();
uiElement
.
addClickListener
(
h
.
onClickBad
);
// error!
Argument of type '(this: Handler, e: Event) => void' is not assignable to parameter of type '(this: void, e: Event) => void'.
The 'this' types of each signature are incompatible.
Type 'void' is not assignable to type 'Handler'.
2345
Argument of type '(this: Handler, e: Event) => void' is not assignable to parameter of type '(this: void, e: Event) => void'.
The 'this' types of each signature are incompatible.
Type 'void' is not assignable to type 'Handler'.
Try
With
this
annotated, you make it explicit that
onClickBad
must be called on an instance of
Handler
.
Then TypeScript will detect that
addClickListener
requires a function that has
this: void
.
To fix the error, change the type of
this
:
ts
class
Handler
{
info
:
string
;
onClickGood
(
this
:
void
,
e
:
Event
) {
// can't use `this` here because it's of type void!
console
.
log
(
"clicked!"
);
}
}
let
h
=
new
Handler
();
uiElement
.
addClickListener
(
h
.
onClickGood
);
Try
Because
onClickGood
specifies its
this
type as
void
, it is legal to pass to
addClickListener
.
Of course, this also means that it can’t use
this.info
.
If you want both then you’ll have to use an arrow function:
ts
class
Handler
{
info
:
string
;
onClickGood
= (
e
:
Event
)
=>
{
this
.
info
=
e
.
message
;
};
}
Try
This works because arrow functions use the outer
this
, so you can always pass them to something that expects
this: void
.
The downside is that one arrow function is created per object of type Handler.
Methods, on the other hand, are only created once and attached to Handler’s prototype.
They are shared between all objects of type Handler.
Overloads
JavaScript is inherently a very dynamic language.
It’s not uncommon for a single JavaScript function to return different types of objects based on the shape of the arguments passed in.
ts
let
suits
= [
"hearts"
,
"spades"
,
"clubs"
,
"diamonds"
];
function
pickCard
(
x
:
any
):
any
{
// Check to see if we're working with an object/array
// if so, they gave us the deck and we'll pick the card
if
(
typeof
x
==
"object"
) {
let
pickedCard
=
Math
.
floor
(
Math
.
random
() *
x
.
length
);
return
pickedCard
;
}
// Otherwise just let them pick the card
else
if
(
typeof
x
==
"number"
) {
let
pickedSuit
=
Math
.
floor
(
x
/
13
);
return
{
suit
:
suits
[
pickedSuit
],
card
:
x
%
13
};
}
}
let
myDeck
= [
{
suit
:
"diamonds"
,
card
:
2
},
{
suit
:
"spades"
,
card
:
10
},
{
suit
:
"hearts"
,
card
:
4
},
];
let
pickedCard1
=
myDeck
[
pickCard
(
myDeck
)];
alert
(
"card: "
+
pickedCard1
.
card
+
" of "
+
pickedCard1
.
suit
);
let
pickedCard2
=
pickCard
(
15
);
alert
(
"card: "
+
pickedCard2
.
card
+
" of "
+
pickedCard2
.
suit
);
Try
Here, the
pickCard
function will return two different things based on what the user has passed in.
If the users passes in an object that represents the deck, the function will pick the card.
If the user picks the card, we tell them which card they’ve picked.
But how do we describe this to the type system?
The answer is to supply multiple function types for the same function as a list of overloads.
This list is what the compiler will use to resolve function calls.
Let’s create a list of overloads that describe what our
pickCard
accepts and what it returns.
ts
let
suits
= [
"hearts"
,
"spades"
,
"clubs"
,
"diamonds"
];
function
pickCard
(
x
: {
suit
:
string
;
card
:
number
}[]):
number
;
function
pickCard
(
x
:
number
): {
suit
:
string
;
card
:
number
};
function
pickCard
(
x
:
any
):
any
{
// Check to see if we're working with an object/array
// if so, they gave us the deck and we'll pick the card
if
(
typeof
x
==
"object"
) {
let
pickedCard
=
Math
.
floor
(
Math
.
random
() *
x
.
length
);
return
pickedCard
;
}
// Otherwise just let them pick the card
else
if
(
typeof
x
==
"number"
) {
let
pickedSuit
=
Math
.
floor
(
x
/
13
);
return
{
suit
:
suits
[
pickedSuit
],
card
:
x
%
13
};
}
}
let
myDeck
= [
{
suit
:
"diamonds"
,
card
:
2
},
{
suit
:
"spades"
,
card
:
10
},
{
suit
:
"hearts"
,
card
:
4
},
];
let
pickedCard1
=
myDeck
[
pickCard
(
myDeck
)];
alert
(
"card: "
+
pickedCard1
.
card
+
" of "
+
pickedCard1
.
suit
);
let
pickedCard2
=
pickCard
(
15
);
alert
(
"card: "
+
pickedCard2
.
card
+
" of "
+
pickedCard2
.
suit
);
Try
With this change, the overloads now give us type checked calls to the
pickCard
function.
In order for the compiler to pick the correct type check, it follows a similar process to the underlying JavaScript.
It looks at the overload list and, proceeding with the first overload, attempts to call the function with the provided parameters.
If it finds a match, it picks this overload as the correct overload.
For this reason, it’s customary to order overloads from most specific to least specific.
Note that the
function pickCard(x): any
piece is not part of the overload list, so it only has two overloads: one that takes an object and one that takes a number.
Calling
pickCard
with any other parameter types would cause an error. |
| Markdown | [Skip to main content](https://www.typescriptlang.org/docs/handbook/functions.html#handbook-content)
[TypeScript](https://www.typescriptlang.org/)
- [Download](https://www.typescriptlang.org/download/)
- [Docs](https://www.typescriptlang.org/docs/)
- [Handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
- [Community](https://www.typescriptlang.org/community/)
- [Playground](https://www.typescriptlang.org/play/)
- [Tools](https://www.typescriptlang.org/tools/)
[in En](https://www.typescriptlang.org/docs/handbook/functions.html)
Was this page helpful?
- Get Started
- [TS for the New Programmer](https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html)
- [TypeScript for JS Programmers](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
- [TS for Java/C\# Programmers](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-oop.html)
- [TS for Functional Programmers](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html)
- [TypeScript Tooling in 5 minutes](https://www.typescriptlang.org/docs/handbook/typescript-tooling-in-5-minutes.html)
- Handbook
- [The TypeScript Handbook](https://www.typescriptlang.org/docs/handbook/intro.html)
- [The Basics](https://www.typescriptlang.org/docs/handbook/2/basic-types.html)
- [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html)
- [Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html)
- [More on Functions](https://www.typescriptlang.org/docs/handbook/2/functions.html)
- [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html)
- Type Manipulation
- [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html)
- [Generics](https://www.typescriptlang.org/docs/handbook/2/generics.html)
- [Keyof Type Operator](https://www.typescriptlang.org/docs/handbook/2/keyof-types.html)
- [Typeof Type Operator](https://www.typescriptlang.org/docs/handbook/2/typeof-types.html)
- [Indexed Access Types](https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html)
- [Conditional Types](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html)
- [Mapped Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)
- [Template Literal Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html)
- [Classes](https://www.typescriptlang.org/docs/handbook/2/classes.html)
- [Modules](https://www.typescriptlang.org/docs/handbook/2/modules.html)
- Reference
- [Utility Types](https://www.typescriptlang.org/docs/handbook/utility-types.html)
- [Cheat Sheets](https://www.typescriptlang.org/cheatsheets/)
- [Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
- [Declaration Merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html)
- [Enums](https://www.typescriptlang.org/docs/handbook/enums.html)
- [Iterators and Generators](https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html)
- [JSX](https://www.typescriptlang.org/docs/handbook/jsx.html)
- [Mixins](https://www.typescriptlang.org/docs/handbook/mixins.html)
- [Namespaces](https://www.typescriptlang.org/docs/handbook/namespaces.html)
- [Namespaces and Modules](https://www.typescriptlang.org/docs/handbook/namespaces-and-modules.html)
- [Symbols](https://www.typescriptlang.org/docs/handbook/symbols.html)
- [Triple-Slash Directives](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html)
- [Type Compatibility](https://www.typescriptlang.org/docs/handbook/type-compatibility.html)
- [Type Inference](https://www.typescriptlang.org/docs/handbook/type-inference.html)
- [Variable Declaration](https://www.typescriptlang.org/docs/handbook/variable-declarations.html)
- Modules Reference
- [Introduction](https://www.typescriptlang.org/docs/handbook/modules/introduction.html)
- [Theory](https://www.typescriptlang.org/docs/handbook/modules/theory.html)
- Guides
- [Choosing Compiler Options](https://www.typescriptlang.org/docs/handbook/modules/guides/choosing-compiler-options.html)
- [Reference](https://www.typescriptlang.org/docs/handbook/modules/reference.html)
- Appendices
- [ESM/CJS Interoperability](https://www.typescriptlang.org/docs/handbook/modules/appendices/esm-cjs-interop.html)
- Tutorials
- [ASP.NET Core](https://www.typescriptlang.org/docs/handbook/asp-net-core.html)
- [Gulp](https://www.typescriptlang.org/docs/handbook/gulp.html)
- [DOM Manipulation](https://www.typescriptlang.org/docs/handbook/dom-manipulation.html)
- [Migrating from JavaScript](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html)
- [Using Babel with TypeScript](https://www.typescriptlang.org/docs/handbook/babel-with-typescript.html)
- What's New
- [TypeScript 6.0](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-6-0.html)
- [TypeScript 5.9](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-9.html)
- [TypeScript 5.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-8.html)
- [TypeScript 5.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-7.html)
- [TypeScript 5.6](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-6.html)
- [TypeScript 5.5](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html)
- [TypeScript 5.4](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-4.html)
- [TypeScript 5.3](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-3.html)
- [TypeScript 5.2](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html)
- [TypeScript 5.1](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-1.html)
- [TypeScript 5.0](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html)
- [TypeScript 4.9](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html)
- [TypeScript 4.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-8.html)
- [TypeScript 4.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-7.html)
- [TypeScript 4.6](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-6.html)
- [TypeScript 4.5](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-5.html)
- [TypeScript 4.4](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-4.html)
- [TypeScript 4.3](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-3.html)
- [TypeScript 4.2](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-2.html)
- [TypeScript 4.1](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-1.html)
- [TypeScript 4.0](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html)
- [TypeScript 3.9](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html)
- [TypeScript 3.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html)
- [TypeScript 3.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html)
- [TypeScript 3.6](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-6.html)
- [TypeScript 3.5](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html)
- [TypeScript 3.4](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html)
- [TypeScript 3.3](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-3.html)
- [TypeScript 3.2](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-2.html)
- [TypeScript 3.1](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-1.html)
- [TypeScript 3.0](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html)
- [TypeScript 2.9](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html)
- [TypeScript 2.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html)
- [TypeScript 2.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html)
- [TypeScript 2.6](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-6.html)
- [TypeScript 2.5](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-5.html)
- [TypeScript 2.4](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html)
- [TypeScript 2.3](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html)
- [TypeScript 2.2](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html)
- [TypeScript 2.1](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html)
- [TypeScript 2.0](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-0.html)
- [TypeScript 1.8](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-8.html)
- [TypeScript 1.7](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-7.html)
- [TypeScript 1.6](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-6.html)
- [TypeScript 1.5](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-5.html)
- [TypeScript 1.4](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-4.html)
- [TypeScript 1.3](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-3.html)
- [TypeScript 1.1](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-1.html)
- Declaration Files
- [Introduction](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html)
- [Declaration Reference](https://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html)
- [Library Structures](https://www.typescriptlang.org/docs/handbook/declaration-files/library-structures.html)
- .d.ts Templates
- [Modules .d.ts](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-d-ts.html)
- [Module: Plugin](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-plugin-d-ts.html)
- [Module: Class](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-class-d-ts.html)
- [Module: Function](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/module-function-d-ts.html)
- [Global .d.ts](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-d-ts.html)
- [Global: Modifying Module](https://www.typescriptlang.org/docs/handbook/declaration-files/templates/global-modifying-module-d-ts.html)
- [Do's and Don'ts](https://www.typescriptlang.org/docs/handbook/declaration-files/do-s-and-don-ts.html)
- [Deep Dive](https://www.typescriptlang.org/docs/handbook/declaration-files/deep-dive.html)
- [Publishing](https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html)
- [Consumption](https://www.typescriptlang.org/docs/handbook/declaration-files/consumption.html)
- JavaScript
- [JS Projects Utilizing TypeScript](https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html)
- [Type Checking JavaScript Files](https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html)
- [JSDoc Reference](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
- [Creating .d.ts Files from .js files](https://www.typescriptlang.org/docs/handbook/declaration-files/dts-from-js.html)
- Project Configuration
- [What is a tsconfig.json](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html)
- [Compiler Options in MSBuild](https://www.typescriptlang.org/docs/handbook/compiler-options-in-msbuild.html)
- [TSConfig Reference](https://www.typescriptlang.org/tsconfig/)
- [tsc CLI Options](https://www.typescriptlang.org/docs/handbook/compiler-options.html)
- [Project References](https://www.typescriptlang.org/docs/handbook/project-references.html)
- [Integrating with Build Tools](https://www.typescriptlang.org/docs/handbook/integrating-with-build-tools.html)
- [Configuring Watch](https://www.typescriptlang.org/docs/handbook/configuring-watch.html)
- [Nightly Builds](https://www.typescriptlang.org/docs/handbook/nightly-builds.html)
### This page has been deprecated
This handbook page has been replaced, [go to the new page](https://www.typescriptlang.org/docs/handbook/2/functions.html)
[Go to new page](https://www.typescriptlang.org/docs/handbook/2/functions.html)
# Functions
Functions are the fundamental building block of any application in JavaScript. They’re how you build up layers of abstraction, mimicking classes, information hiding, and modules. In TypeScript, while there are classes, namespaces, and modules, functions still play the key role in describing how to *do* things. TypeScript also adds some new capabilities to the standard JavaScript functions to make them easier to work with.
## Functions
To begin, just as in JavaScript, TypeScript functions can be created both as a named function or as an anonymous function. This allows you to choose the most appropriate approach for your application, whether you’re building a list of functions in an API or a one-off function to hand off to another function.
To quickly recap what these two approaches look like in JavaScript:
```
ts// Named functionfunction add ( x , y ) {return x + y ;}// Anonymous functionlet myAdd = function ( x , y ) {return x + y ;};Try
```
Just as in JavaScript, functions can refer to variables outside of the function body. When they do so, they’re said to *capture* these variables. While understanding how this works (and the trade-offs when using this technique) is outside of the scope of this article, having a firm understanding how this mechanic works is an important piece of working with JavaScript and TypeScript.
```
tslet z = 100;function addToZ ( x , y ) {return x + y + z ;}Try
```
## Function Types
### Typing the function
Let’s add types to our simple examples from earlier:
```
tsfunction add ( x : number, y : number): number {return x + y ;}let myAdd = function ( x : number, y : number): number {return x + y ;};Try
```
We can add types to each of the parameters and then to the function itself to add a return type. TypeScript can figure the return type out by looking at the return statements, so we can also optionally leave this off in many cases.
### Writing the function type
Now that we’ve typed the function, let’s write the full type of the function out by looking at each piece of the function type.
```
tslet myAdd : ( x : number, y : number) => number = function (x : number,y : number): number {return x + y ;};Try
```
A function’s type has the same two parts: the type of the arguments and the return type. When writing out the whole function type, both parts are required. We write out the parameter types just like a parameter list, giving each parameter a name and a type. This name is just to help with readability. We could have instead written:
```
tslet myAdd : ( baseValue : number, increment : number) => number = function (x : number,y : number): number {return x + y ;};Try
```
As long as the parameter types line up, it’s considered a valid type for the function, regardless of the names you give the parameters in the function type.
The second part is the return type. We make it clear which is the return type by using an arrow (`=>`) between the parameters and the return type. As mentioned before, this is a required part of the function type, so if the function doesn’t return a value, you would use `void` instead of leaving it off.
Of note, only the parameters and the return type make up the function type. Captured variables are not reflected in the type. In effect, captured variables are part of the “hidden state” of any function and do not make up its API.
### Inferring the types
In playing with the example, you may notice that the TypeScript compiler can figure out the type even if you only have types on one side of the equation:
```
ts// The parameters 'x' and 'y' have the type numberlet myAdd = function ( x : number, y : number): number {return x + y ;};// myAdd has the full function typelet myAdd2 : ( baseValue : number, increment : number) => number = function ( x , y ) {return x + y ;};Try
```
This is called “contextual typing”, a form of type inference. This helps cut down on the amount of effort to keep your program typed.
## Optional and Default Parameters
In TypeScript, every parameter is assumed to be required by the function. This doesn’t mean that it can’t be given `null` or `undefined`, but rather, when the function is called, the compiler will check that the user has provided a value for each parameter. The compiler also assumes that these parameters are the only parameters that will be passed to the function. In short, the number of arguments given to a function has to match the number of parameters the function expects.
```
tsfunction buildName ( firstName : string, lastName : string) {return firstName + " " + lastName ;}let result1 = buildName ("Bob"); // error, too few parametersExpected 2 arguments, but got 1.2554Expected 2 arguments, but got 1.let result2 = buildName ("Bob", "Adams", "Sr." ); // error, too many parametersExpected 2 arguments, but got 3.2554Expected 2 arguments, but got 3.let result3 = buildName ("Bob", "Adams"); // ah, just rightTry
```
In JavaScript, every parameter is optional, and users may leave them off as they see fit. When they do, their value is `undefined`. We can get this functionality in TypeScript by adding a `?` to the end of parameters we want to be optional. For example, let’s say we want the last name parameter from above to be optional:
```
tsfunction buildName ( firstName : string, lastName ?: string) {if ( lastName ) return firstName + " " + lastName ;else return firstName ;}let result1 = buildName ("Bob"); // works correctly nowlet result2 = buildName ("Bob", "Adams", "Sr." ); // error, too many parametersExpected 1-2 arguments, but got 3.2554Expected 1-2 arguments, but got 3.let result3 = buildName ("Bob", "Adams"); // ah, just rightTry
```
Any optional parameters must follow required parameters. Had we wanted to make the first name optional, rather than the last name, we would need to change the order of parameters in the function, putting the first name last in the list.
In TypeScript, we can also set a value that a parameter will be assigned if the user does not provide one, or if the user passes `undefined` in its place. These are called default-initialized parameters. Let’s take the previous example and default the last name to `"Smith"`.
```
tsfunction buildName ( firstName : string, lastName = "Smith") {return firstName + " " + lastName ;}let result1 = buildName ("Bob"); // works correctly now, returns "Bob Smith"let result2 = buildName ("Bob", undefined ); // still works, also returns "Bob Smith"let result3 = buildName ("Bob", "Adams", "Sr." ); // error, too many parametersExpected 1-2 arguments, but got 3.2554Expected 1-2 arguments, but got 3.let result4 = buildName ("Bob", "Adams"); // ah, just rightTry
```
Default-initialized parameters that come after all required parameters are treated as optional, and just like optional parameters, can be omitted when calling their respective function. This means optional parameters and trailing default parameters will share commonality in their types, so both
```
tsfunction buildName(firstName: string, lastName?: string) {// ...}
```
and
```
tsfunction buildName(firstName: string, lastName = "Smith") {// ...}
```
share the same type `(firstName: string, lastName?: string) => string`. The default value of `lastName` disappears in the type, only leaving behind the fact that the parameter is optional.
Unlike plain optional parameters, default-initialized parameters don’t *need* to occur after required parameters. If a default-initialized parameter comes before a required parameter, users need to explicitly pass `undefined` to get the default initialized value. For example, we could write our last example with only a default initializer on `firstName`:
```
tsfunction buildName ( firstName = "Will", lastName : string) {return firstName + " " + lastName ;}let result1 = buildName ("Bob"); // error, too few parametersExpected 2 arguments, but got 1.2554Expected 2 arguments, but got 1.let result2 = buildName ("Bob", "Adams", "Sr." ); // error, too many parametersExpected 2 arguments, but got 3.2554Expected 2 arguments, but got 3.let result3 = buildName ("Bob", "Adams"); // okay and returns "Bob Adams"let result4 = buildName ( undefined , "Adams"); // okay and returns "Will Adams"Try
```
### Rest Parameters
Required, optional, and default parameters all have one thing in common: they talk about one parameter at a time. Sometimes, you want to work with multiple parameters as a group, or you may not know how many parameters a function will ultimately take. In JavaScript, you can work with the arguments directly using the `arguments` variable that is visible inside every function body.
In TypeScript, you can gather these arguments together into a variable:
```
tsfunction buildName ( firstName : string, ... restOfName : string[]) {return firstName + " " + restOfName . join (" ");}// employeeName will be "Joseph Samuel Lucas MacKinzie"let employeeName = buildName ("Joseph", "Samuel", "Lucas", "MacKinzie");Try
```
*Rest parameters* are treated as a boundless number of optional parameters. When passing arguments for a rest parameter, you can use as many as you want; you can even pass none. The compiler will build an array of the arguments passed in with the name given after the ellipsis (`...`), allowing you to use it in your function.
The ellipsis is also used in the type of the function with rest parameters:
```
tsfunction buildName ( firstName : string, ... restOfName : string[]) {return firstName + " " + restOfName . join (" ");}let buildNameFun : ( fname : string, ... rest : string[]) => string = buildName ;Try
```
## `this`
Learning how to use `this` in JavaScript is something of a rite of passage. Since TypeScript is a superset of JavaScript, TypeScript developers also need to learn how to use `this` and how to spot when it’s not being used correctly. Fortunately, TypeScript lets you catch incorrect uses of `this` with a couple of techniques. If you need to learn how `this` works in JavaScript, though, first read Yehuda Katz’s [Understanding JavaScript Function Invocation and “this”](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/). Yehuda’s article explains the inner workings of `this` very well, so we’ll just cover the basics here.
### `this` and arrow functions
In JavaScript, `this` is a variable that’s set when a function is called. This makes it a very powerful and flexible feature, but it comes at the cost of always having to know about the context that a function is executing in. This is notoriously confusing, especially when returning a function or passing a function as an argument.
Let’s look at an example:
```
tslet deck = {suits : ["hearts", "spades", "clubs", "diamonds"],cards : Array (52),createCardPicker : function () {return function () {let pickedCard = Math . floor ( Math . random () * 52);let pickedSuit = Math . floor ( pickedCard / 13);return { suit : this. suits [ pickedSuit ], card : pickedCard % 13 };};},};let cardPicker = deck . createCardPicker ();let pickedCard = cardPicker ();alert ("card: " + pickedCard . card + " of " + pickedCard . suit );Try
```
Notice that `createCardPicker` is a function that itself returns a function. If we tried to run the example, we would get an error instead of the expected alert box. This is because the `this` being used in the function created by `createCardPicker` will be set to `window` instead of our `deck` object. That’s because we call `cardPicker()` on its own. A top-level non-method syntax call like this will use `window` for `this`. (Note: under strict mode, `this` will be `undefined` rather than `window`).
We can fix this by making sure the function is bound to the correct `this` before we return the function to be used later. This way, regardless of how it’s later used, it will still be able to see the original `deck` object. To do this, we change the function expression to use the ECMAScript 6 arrow syntax. Arrow functions capture the `this` where the function is created rather than where it is invoked:
```
tslet deck = {suits : ["hearts", "spades", "clubs", "diamonds"],cards : Array (52),createCardPicker : function () {// NOTE: the line below is now an arrow function, allowing us to capture 'this' right herereturn () => {let pickedCard = Math . floor ( Math . random () * 52);let pickedSuit = Math . floor ( pickedCard / 13);return { suit : this. suits [ pickedSuit ], card : pickedCard % 13 };};},};let cardPicker = deck . createCardPicker ();let pickedCard = cardPicker ();alert ("card: " + pickedCard . card + " of " + pickedCard . suit );Try
```
Even better, TypeScript will warn you when you make this mistake if you pass the [`noImplicitThis`](https://www.typescriptlang.org/tsconfig#noImplicitThis) flag to the compiler. It will point out that `this` in `this.suits[pickedSuit]` is of type `any`.
### `this` parameters
Unfortunately, the type of `this.suits[pickedSuit]` is still `any`. That’s because `this` comes from the function expression inside the object literal. To fix this, you can provide an explicit `this` parameter. `this` parameters are fake parameters that come first in the parameter list of a function:
```
tsfunction f(this: void) {// make sure `this` is unusable in this standalone function}
```
Let’s add a couple of interfaces to our example above, `Card` and `Deck`, to make the types clearer and easier to reuse:
```
tsinterface Card {suit : string;card : number;}interface Deck {suits : string[];cards : number[];createCardPicker ( this : Deck ): () => Card ;}let deck : Deck = {suits : ["hearts", "spades", "clubs", "diamonds"],cards : Array (52),// NOTE: The function now explicitly specifies that its callee must be of type DeckcreateCardPicker : function ( this : Deck ) {return () => {let pickedCard = Math . floor ( Math . random () * 52);let pickedSuit = Math . floor ( pickedCard / 13);return { suit : this. suits [ pickedSuit ], card : pickedCard % 13 };};},};let cardPicker = deck . createCardPicker ();let pickedCard = cardPicker ();alert ("card: " + pickedCard . card + " of " + pickedCard . suit );Try
```
Now TypeScript knows that `createCardPicker` expects to be called on a `Deck` object. That means that `this` is of type `Deck` now, not `any`, so [`noImplicitThis`](https://www.typescriptlang.org/tsconfig#noImplicitThis) will not cause any errors.
#### `this` parameters in callbacks
You can also run into errors with `this` in callbacks, when you pass functions to a library that will later call them. Because the library that calls your callback will call it like a normal function, `this` will be `undefined`. With some work you can use `this` parameters to prevent errors with callbacks too. First, the library author needs to annotate the callback type with `this`:
```
tsinterface UIElement {addClickListener ( onclick : ( this : void, e : Event ) => void): void;}Try
```
`this: void` means that `addClickListener` expects `onclick` to be a function that does not require a `this` type. Second, annotate your calling code with `this`:
```
tsTry
```
With `this` annotated, you make it explicit that `onClickBad` must be called on an instance of `Handler`. Then TypeScript will detect that `addClickListener` requires a function that has `this: void`. To fix the error, change the type of `this`:
```
tsclass Handler {info : string;onClickGood ( this : void, e : Event ) {// can't use `this` here because it's of type void!console . log ("clicked!");}}let h = new Handler ();uiElement . addClickListener ( h . onClickGood );Try
```
Because `onClickGood` specifies its `this` type as `void`, it is legal to pass to `addClickListener`. Of course, this also means that it can’t use `this.info`. If you want both then you’ll have to use an arrow function:
```
tsclass Handler {info : string;onClickGood = ( e : Event ) => {this. info = e . message ;};}Try
```
This works because arrow functions use the outer `this`, so you can always pass them to something that expects `this: void`. The downside is that one arrow function is created per object of type Handler. Methods, on the other hand, are only created once and attached to Handler’s prototype. They are shared between all objects of type Handler.
## Overloads
JavaScript is inherently a very dynamic language. It’s not uncommon for a single JavaScript function to return different types of objects based on the shape of the arguments passed in.
```
tslet suits = ["hearts", "spades", "clubs", "diamonds"];function pickCard ( x : any): any {// Check to see if we're working with an object/array// if so, they gave us the deck and we'll pick the cardif (typeof x == "object") {let pickedCard = Math . floor ( Math . random () * x . length );return pickedCard ;}// Otherwise just let them pick the cardelse if (typeof x == "number") {let pickedSuit = Math . floor ( x / 13);return { suit : suits [ pickedSuit ], card : x % 13 };}}let myDeck = [{ suit : "diamonds", card : 2 },{ suit : "spades", card : 10 },{ suit : "hearts", card : 4 },];let pickedCard1 = myDeck [ pickCard ( myDeck )];alert ("card: " + pickedCard1 . card + " of " + pickedCard1 . suit );let pickedCard2 = pickCard (15);alert ("card: " + pickedCard2 . card + " of " + pickedCard2 . suit );Try
```
Here, the `pickCard` function will return two different things based on what the user has passed in. If the users passes in an object that represents the deck, the function will pick the card. If the user picks the card, we tell them which card they’ve picked. But how do we describe this to the type system?
The answer is to supply multiple function types for the same function as a list of overloads. This list is what the compiler will use to resolve function calls. Let’s create a list of overloads that describe what our `pickCard` accepts and what it returns.
```
tslet suits = ["hearts", "spades", "clubs", "diamonds"];function pickCard ( x : { suit : string; card : number }[]): number;function pickCard ( x : number): { suit : string; card : number };function pickCard ( x : any): any {// Check to see if we're working with an object/array// if so, they gave us the deck and we'll pick the cardif (typeof x == "object") {let pickedCard = Math . floor ( Math . random () * x . length );return pickedCard ;}// Otherwise just let them pick the cardelse if (typeof x == "number") {let pickedSuit = Math . floor ( x / 13);return { suit : suits [ pickedSuit ], card : x % 13 };}}let myDeck = [{ suit : "diamonds", card : 2 },{ suit : "spades", card : 10 },{ suit : "hearts", card : 4 },];let pickedCard1 = myDeck [ pickCard ( myDeck )];alert ("card: " + pickedCard1 . card + " of " + pickedCard1 . suit );let pickedCard2 = pickCard (15);alert ("card: " + pickedCard2 . card + " of " + pickedCard2 . suit );Try
```
With this change, the overloads now give us type checked calls to the `pickCard` function.
In order for the compiler to pick the correct type check, it follows a similar process to the underlying JavaScript. It looks at the overload list and, proceeding with the first overload, attempts to call the function with the provided parameters. If it finds a match, it picks this overload as the correct overload. For this reason, it’s customary to order overloads from most specific to least specific.
Note that the `function pickCard(x): any` piece is not part of the overload list, so it only has two overloads: one that takes an object and one that takes a number. Calling `pickCard` with any other parameter types would cause an error.
##### On this page
- [Functions](https://www.typescriptlang.org/docs/handbook/functions.html#functions)
- [Function Types](https://www.typescriptlang.org/docs/handbook/functions.html#function-types)
- [Typing the function](https://www.typescriptlang.org/docs/handbook/functions.html#typing-the-function)
- [Writing the function type](https://www.typescriptlang.org/docs/handbook/functions.html#writing-the-function-type)
- [Inferring the types](https://www.typescriptlang.org/docs/handbook/functions.html#inferring-the-types)
- [Optional and Default Parameters](https://www.typescriptlang.org/docs/handbook/functions.html#optional-and-default-parameters)
- [Rest Parameters](https://www.typescriptlang.org/docs/handbook/functions.html#rest-parameters)
- [this](https://www.typescriptlang.org/docs/handbook/functions.html#this)
- [this and arrow functions](https://www.typescriptlang.org/docs/handbook/functions.html#this-and-arrow-functions)
- [this parameters](https://www.typescriptlang.org/docs/handbook/functions.html#this-parameters)
- [Overloads](https://www.typescriptlang.org/docs/handbook/functions.html#overloads)
##### Is this page helpful?
Yes
No
The TypeScript docs are an open source project. Help us improve these pages [by sending a Pull Request](https://github.com/microsoft/TypeScript-Website/blob/v2/packages/documentation/copy/en/handbook-v1/Functions.md) ❤
Contributors to this page:
RC
DR
OT
NS
MF
24+
Last updated: Apr 13, 2026
This page loaded in 0.024 seconds.
### Customize
Site Colours:
Code Font:
### Popular Documentation Pages
- [Everyday Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html)
All of the common types in TypeScript
- [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html)
Techniques to make more elegant types
- [More on Functions](https://www.typescriptlang.org/docs/handbook/2/functions.html)
How to provide types to functions in JavaScript
- [More on Objects](https://www.typescriptlang.org/docs/handbook/2/objects.html)
How to provide a type shape to JavaScript objects
- [Narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html)
How TypeScript infers types based on runtime behavior
- [Variable Declarations](https://www.typescriptlang.org/docs/handbook/variable-declarations.html)
How to create and type JavaScript variables
- [TypeScript in 5 minutes](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
An overview of building a TypeScript web app
- [TSConfig Options](https://www.typescriptlang.org/tsconfig/)
All the configuration options for a project
- [Classes](https://www.typescriptlang.org/docs/handbook/2/classes.html)
How to provide types to JavaScript ES6 classes
Made with ♥ in Redmond, Boston, SF & Dublin
[](https://www.typescriptlang.org/docs/handbook/functions.html)
© 2012-2026 Microsoft
[Privacy](https://go.microsoft.com/fwlink/?LinkId=521839 "Microsoft Privacy Policy")[Terms of Use](https://go.microsoft.com/fwlink/?LinkID=206977)
### Using TypeScript
- [Get Started](https://www.typescriptlang.org/docs/)
- [Download](https://www.typescriptlang.org/download/)
- [Community](https://www.typescriptlang.org/community/)
- [Playground](https://www.typescriptlang.org/play/)
- [TSConfig Ref](https://www.typescriptlang.org/tsconfig/)
- [Code Samples](https://www.typescriptlang.org/play/#show-examples)
- [Why TypeScript](https://www.typescriptlang.org/why-create-typescript/)
- [Design](https://www.typescriptlang.org/branding/)
### Community
- [Get Help](https://www.typescriptlang.org/community)
- [Blog](https://devblogs.microsoft.com/typescript/)
- [GitHub Repo](https://github.com/microsoft/TypeScript/#readme)
- [Community Chat](https://discord.gg/typescript)
- [@TypeScript](https://twitter.com/TypeScript)
- [Mastodon](https://fosstodon.org/@TypeScript)
- [Stack Overflow](https://stackoverflow.com/questions/tagged/typescript)
- [Web Repo](https://github.com/microsoft/TypeScript-Website)
MSG |
| Readable Markdown | Functions are the fundamental building block of any application in JavaScript. They’re how you build up layers of abstraction, mimicking classes, information hiding, and modules. In TypeScript, while there are classes, namespaces, and modules, functions still play the key role in describing how to *do* things. TypeScript also adds some new capabilities to the standard JavaScript functions to make them easier to work with.
## Functions
To begin, just as in JavaScript, TypeScript functions can be created both as a named function or as an anonymous function. This allows you to choose the most appropriate approach for your application, whether you’re building a list of functions in an API or a one-off function to hand off to another function.
To quickly recap what these two approaches look like in JavaScript:
```
ts// Named functionfunction add(x, y) {return x + y;}// Anonymous functionlet myAdd = function (x, y) {return x + y;};Try
```
Just as in JavaScript, functions can refer to variables outside of the function body. When they do so, they’re said to *capture* these variables. While understanding how this works (and the trade-offs when using this technique) is outside of the scope of this article, having a firm understanding how this mechanic works is an important piece of working with JavaScript and TypeScript.
```
tslet z = 100;function addToZ(x, y) {return x + y + z;}Try
```
## Function Types
### Typing the function
Let’s add types to our simple examples from earlier:
```
tsfunction add(x: number, y: number): number {return x + y;}let myAdd = function (x: number, y: number): number {return x + y;};Try
```
We can add types to each of the parameters and then to the function itself to add a return type. TypeScript can figure the return type out by looking at the return statements, so we can also optionally leave this off in many cases.
### Writing the function type
Now that we’ve typed the function, let’s write the full type of the function out by looking at each piece of the function type.
```
tslet myAdd: (x: number, y: number) => number = function (x: number,y: number): number {return x + y;};Try
```
A function’s type has the same two parts: the type of the arguments and the return type. When writing out the whole function type, both parts are required. We write out the parameter types just like a parameter list, giving each parameter a name and a type. This name is just to help with readability. We could have instead written:
```
tslet myAdd: (baseValue: number, increment: number) => number = function (x: number,y: number): number {return x + y;};Try
```
As long as the parameter types line up, it’s considered a valid type for the function, regardless of the names you give the parameters in the function type.
The second part is the return type. We make it clear which is the return type by using an arrow (`=>`) between the parameters and the return type. As mentioned before, this is a required part of the function type, so if the function doesn’t return a value, you would use `void` instead of leaving it off.
Of note, only the parameters and the return type make up the function type. Captured variables are not reflected in the type. In effect, captured variables are part of the “hidden state” of any function and do not make up its API.
### Inferring the types
In playing with the example, you may notice that the TypeScript compiler can figure out the type even if you only have types on one side of the equation:
```
ts// The parameters 'x' and 'y' have the type numberlet myAdd = function (x: number, y: number): number {return x + y;};// myAdd has the full function typelet myAdd2: (baseValue: number, increment: number) => number = function (x, y) {return x + y;};Try
```
This is called “contextual typing”, a form of type inference. This helps cut down on the amount of effort to keep your program typed.
## Optional and Default Parameters
In TypeScript, every parameter is assumed to be required by the function. This doesn’t mean that it can’t be given `null` or `undefined`, but rather, when the function is called, the compiler will check that the user has provided a value for each parameter. The compiler also assumes that these parameters are the only parameters that will be passed to the function. In short, the number of arguments given to a function has to match the number of parameters the function expects.
```
tsfunction buildName(firstName: string, lastName: string) {return firstName + " " + lastName;}let result1 = buildName("Bob"); // error, too few parametersExpected 2 arguments, but got 1.2554Expected 2 arguments, but got 1.let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parametersExpected 2 arguments, but got 3.2554Expected 2 arguments, but got 3.let result3 = buildName("Bob", "Adams"); // ah, just rightTry
```
In JavaScript, every parameter is optional, and users may leave them off as they see fit. When they do, their value is `undefined`. We can get this functionality in TypeScript by adding a `?` to the end of parameters we want to be optional. For example, let’s say we want the last name parameter from above to be optional:
```
tsfunction buildName(firstName: string, lastName?: string) {if (lastName) return firstName + " " + lastName;else return firstName;}let result1 = buildName("Bob"); // works correctly nowlet result2 = buildName("Bob", "Adams", "Sr."); // error, too many parametersExpected 1-2 arguments, but got 3.2554Expected 1-2 arguments, but got 3.let result3 = buildName("Bob", "Adams"); // ah, just rightTry
```
Any optional parameters must follow required parameters. Had we wanted to make the first name optional, rather than the last name, we would need to change the order of parameters in the function, putting the first name last in the list.
In TypeScript, we can also set a value that a parameter will be assigned if the user does not provide one, or if the user passes `undefined` in its place. These are called default-initialized parameters. Let’s take the previous example and default the last name to `"Smith"`.
```
tsfunction buildName(firstName: string, lastName = "Smith") {return firstName + " " + lastName;}let result1 = buildName("Bob"); // works correctly now, returns "Bob Smith"let result2 = buildName("Bob", undefined); // still works, also returns "Bob Smith"let result3 = buildName("Bob", "Adams", "Sr."); // error, too many parametersExpected 1-2 arguments, but got 3.2554Expected 1-2 arguments, but got 3.let result4 = buildName("Bob", "Adams"); // ah, just rightTry
```
Default-initialized parameters that come after all required parameters are treated as optional, and just like optional parameters, can be omitted when calling their respective function. This means optional parameters and trailing default parameters will share commonality in their types, so both
```
tsfunction buildName(firstName: string, lastName?: string) {// ...}
```
and
```
tsfunction buildName(firstName: string, lastName = "Smith") {// ...}
```
share the same type `(firstName: string, lastName?: string) => string`. The default value of `lastName` disappears in the type, only leaving behind the fact that the parameter is optional.
Unlike plain optional parameters, default-initialized parameters don’t *need* to occur after required parameters. If a default-initialized parameter comes before a required parameter, users need to explicitly pass `undefined` to get the default initialized value. For example, we could write our last example with only a default initializer on `firstName`:
```
tsfunction buildName(firstName = "Will", lastName: string) {return firstName + " " + lastName;}let result1 = buildName("Bob"); // error, too few parametersExpected 2 arguments, but got 1.2554Expected 2 arguments, but got 1.let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parametersExpected 2 arguments, but got 3.2554Expected 2 arguments, but got 3.let result3 = buildName("Bob", "Adams"); // okay and returns "Bob Adams"let result4 = buildName(undefined, "Adams"); // okay and returns "Will Adams"Try
```
### Rest Parameters
Required, optional, and default parameters all have one thing in common: they talk about one parameter at a time. Sometimes, you want to work with multiple parameters as a group, or you may not know how many parameters a function will ultimately take. In JavaScript, you can work with the arguments directly using the `arguments` variable that is visible inside every function body.
In TypeScript, you can gather these arguments together into a variable:
```
tsfunction buildName(firstName: string, ...restOfName: string[]) {return firstName + " " + restOfName.join(" ");}// employeeName will be "Joseph Samuel Lucas MacKinzie"let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");Try
```
*Rest parameters* are treated as a boundless number of optional parameters. When passing arguments for a rest parameter, you can use as many as you want; you can even pass none. The compiler will build an array of the arguments passed in with the name given after the ellipsis (`...`), allowing you to use it in your function.
The ellipsis is also used in the type of the function with rest parameters:
```
tsfunction buildName(firstName: string, ...restOfName: string[]) {return firstName + " " + restOfName.join(" ");}let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;Try
```
## `this`
Learning how to use `this` in JavaScript is something of a rite of passage. Since TypeScript is a superset of JavaScript, TypeScript developers also need to learn how to use `this` and how to spot when it’s not being used correctly. Fortunately, TypeScript lets you catch incorrect uses of `this` with a couple of techniques. If you need to learn how `this` works in JavaScript, though, first read Yehuda Katz’s [Understanding JavaScript Function Invocation and “this”](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/). Yehuda’s article explains the inner workings of `this` very well, so we’ll just cover the basics here.
### `this` and arrow functions
In JavaScript, `this` is a variable that’s set when a function is called. This makes it a very powerful and flexible feature, but it comes at the cost of always having to know about the context that a function is executing in. This is notoriously confusing, especially when returning a function or passing a function as an argument.
Let’s look at an example:
```
tslet deck = {suits : ["hearts", "spades", "clubs", "diamonds"],cards : Array(52),createCardPicker: function () {return function () {let pickedCard = Math.floor(Math.random() * 52);let pickedSuit = Math.floor(pickedCard / 13);return { suit : this.suits[pickedSuit], card : pickedCard % 13 };};},};let cardPicker = deck.createCardPicker();let pickedCard = cardPicker();alert("card: " + pickedCard.card + " of " + pickedCard.suit);Try
```
Notice that `createCardPicker` is a function that itself returns a function. If we tried to run the example, we would get an error instead of the expected alert box. This is because the `this` being used in the function created by `createCardPicker` will be set to `window` instead of our `deck` object. That’s because we call `cardPicker()` on its own. A top-level non-method syntax call like this will use `window` for `this`. (Note: under strict mode, `this` will be `undefined` rather than `window`).
We can fix this by making sure the function is bound to the correct `this` before we return the function to be used later. This way, regardless of how it’s later used, it will still be able to see the original `deck` object. To do this, we change the function expression to use the ECMAScript 6 arrow syntax. Arrow functions capture the `this` where the function is created rather than where it is invoked:
```
tslet deck = {suits : ["hearts", "spades", "clubs", "diamonds"],cards : Array(52),createCardPicker: function () {// NOTE: the line below is now an arrow function, allowing us to capture 'this' right herereturn () => {let pickedCard = Math.floor(Math.random() * 52);let pickedSuit = Math.floor(pickedCard / 13);return { suit : this.suits[pickedSuit], card : pickedCard % 13 };};},};let cardPicker = deck.createCardPicker();let pickedCard = cardPicker();alert("card: " + pickedCard.card + " of " + pickedCard.suit);Try
```
Even better, TypeScript will warn you when you make this mistake if you pass the [`noImplicitThis`](https://www.typescriptlang.org/tsconfig#noImplicitThis) flag to the compiler. It will point out that `this` in `this.suits[pickedSuit]` is of type `any`.
### `this` parameters
Unfortunately, the type of `this.suits[pickedSuit]` is still `any`. That’s because `this` comes from the function expression inside the object literal. To fix this, you can provide an explicit `this` parameter. `this` parameters are fake parameters that come first in the parameter list of a function:
```
tsfunction f(this: void) {// make sure `this` is unusable in this standalone function}
```
Let’s add a couple of interfaces to our example above, `Card` and `Deck`, to make the types clearer and easier to reuse:
```
tsinterface Card {suit: string;card: number;}interface Deck {suits: string[];cards: number[];createCardPicker(this: Deck): () => Card;}let deck: Deck = {suits : ["hearts", "spades", "clubs", "diamonds"],cards : Array(52),// NOTE: The function now explicitly specifies that its callee must be of type DeckcreateCardPicker: function (this: Deck) {return () => {let pickedCard = Math.floor(Math.random() * 52);let pickedSuit = Math.floor(pickedCard / 13);return { suit : this.suits[pickedSuit], card : pickedCard % 13 };};},};let cardPicker = deck.createCardPicker();let pickedCard = cardPicker();alert("card: " + pickedCard.card + " of " + pickedCard.suit);Try
```
Now TypeScript knows that `createCardPicker` expects to be called on a `Deck` object. That means that `this` is of type `Deck` now, not `any`, so [`noImplicitThis`](https://www.typescriptlang.org/tsconfig#noImplicitThis) will not cause any errors.
#### `this` parameters in callbacks
You can also run into errors with `this` in callbacks, when you pass functions to a library that will later call them. Because the library that calls your callback will call it like a normal function, `this` will be `undefined`. With some work you can use `this` parameters to prevent errors with callbacks too. First, the library author needs to annotate the callback type with `this`:
```
tsinterface UIElement {addClickListener(onclick: (this: void, e: Event) => void): void;}Try
```
`this: void` means that `addClickListener` expects `onclick` to be a function that does not require a `this` type. Second, annotate your calling code with `this`:
```
tsTry
```
With `this` annotated, you make it explicit that `onClickBad` must be called on an instance of `Handler`. Then TypeScript will detect that `addClickListener` requires a function that has `this: void`. To fix the error, change the type of `this`:
```
tsclass Handler {info: string;onClickGood(this: void, e: Event) {// can't use `this` here because it's of type void!console.log("clicked!");}}let h = new Handler();uiElement.addClickListener(h.onClickGood);Try
```
Because `onClickGood` specifies its `this` type as `void`, it is legal to pass to `addClickListener`. Of course, this also means that it can’t use `this.info`. If you want both then you’ll have to use an arrow function:
```
tsclass Handler {info: string;onClickGood = (e: Event) => {this.info = e.message;};}Try
```
This works because arrow functions use the outer `this`, so you can always pass them to something that expects `this: void`. The downside is that one arrow function is created per object of type Handler. Methods, on the other hand, are only created once and attached to Handler’s prototype. They are shared between all objects of type Handler.
## Overloads
JavaScript is inherently a very dynamic language. It’s not uncommon for a single JavaScript function to return different types of objects based on the shape of the arguments passed in.
```
tslet suits = ["hearts", "spades", "clubs", "diamonds"];function pickCard(x: any): any {// Check to see if we're working with an object/array// if so, they gave us the deck and we'll pick the cardif (typeof x == "object") {let pickedCard = Math.floor(Math.random() * x.length);return pickedCard;}// Otherwise just let them pick the cardelse if (typeof x == "number") {let pickedSuit = Math.floor(x / 13);return { suit : suits[pickedSuit], card : x % 13 };}}let myDeck = [{ suit : "diamonds", card : 2 },{ suit : "spades", card : 10 },{ suit : "hearts", card : 4 },];let pickedCard1 = myDeck[pickCard(myDeck)];alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);let pickedCard2 = pickCard(15);alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);Try
```
Here, the `pickCard` function will return two different things based on what the user has passed in. If the users passes in an object that represents the deck, the function will pick the card. If the user picks the card, we tell them which card they’ve picked. But how do we describe this to the type system?
The answer is to supply multiple function types for the same function as a list of overloads. This list is what the compiler will use to resolve function calls. Let’s create a list of overloads that describe what our `pickCard` accepts and what it returns.
```
tslet suits = ["hearts", "spades", "clubs", "diamonds"];function pickCard(x: { suit: string; card: number }[]): number;function pickCard(x: number): { suit: string; card: number };function pickCard(x: any): any {// Check to see if we're working with an object/array// if so, they gave us the deck and we'll pick the cardif (typeof x == "object") {let pickedCard = Math.floor(Math.random() * x.length);return pickedCard;}// Otherwise just let them pick the cardelse if (typeof x == "number") {let pickedSuit = Math.floor(x / 13);return { suit : suits[pickedSuit], card : x % 13 };}}let myDeck = [{ suit : "diamonds", card : 2 },{ suit : "spades", card : 10 },{ suit : "hearts", card : 4 },];let pickedCard1 = myDeck[pickCard(myDeck)];alert("card: " + pickedCard1.card + " of " + pickedCard1.suit);let pickedCard2 = pickCard(15);alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);Try
```
With this change, the overloads now give us type checked calls to the `pickCard` function.
In order for the compiler to pick the correct type check, it follows a similar process to the underlying JavaScript. It looks at the overload list and, proceeding with the first overload, attempts to call the function with the provided parameters. If it finds a match, it picks this overload as the correct overload. For this reason, it’s customary to order overloads from most specific to least specific.
Note that the `function pickCard(x): any` piece is not part of the overload list, so it only has two overloads: one that takes an object and one that takes a number. Calling `pickCard` with any other parameter types would cause an error. |
| Shard | 42 (laksa) |
| Root Hash | 17921559718398937842 |
| Unparsed URL | org,typescriptlang!www,/docs/handbook/functions.html s443 |