TypeScript function parameters allow you to define the types of the values that are passed into a function, which helps with type checking and improves code clarity. In addition to basic parameter syntax, TypeScript supports optional and default parameters, as well as nullable types.
These features enable you to write more flexible and robust code by allowing for the possibility of
undefined
or
null
values, and by providing default values when no value is passed in.
Function parameters
TypeScript is a superset of JavaScript that adds static types to the language. One of the benefits of TypeScript is that it allows us to specify the types of the parameters and the return value of a function, which can help us catch errors and improve readability.
A TypeScript function type is composed of the types of the parameters and the return type, separated by a
=>
symbol. For example:
type StringToNumber = (s: string) => number;
const parseNumber = (s: string) => Number(s);
You can also use an interface or a type alias to name a function type:
interface GreetFunction {
(name: string): void;
type AddFunction = (x: number, y: number) => number;
You can use these named types to annotate the parameters and the return value of a function declaration or expression:
function greet(name: string): GreetFunction {
return () => console.log(`Hello, ${name}!`);
const add: AddFunction = (x, y) => x + y;
You can also use an anonymous function type to directly annotate the parameters and the return value of a function:
function greet(name: string): (message: string) => void {
return (message) => console.log(`${name}, ${message}!`);
const add = (x: number, y: number): number => x + y;
Optional parameters
You can mark some parameters as optional by adding a
?
after their names. This means that these parameters are not required when calling the function, and their values may be
undefined
inside the function body. For example:
function sayHello(name?: string) {
if (name) {
console.log(`Hello, ${name}!`);
} else {
console.log("Hello, stranger!");
sayHello("Alice");
sayHello();
Note that optional parameters must come after required parameters in a function type. For example, this is valid:
type GreetFunction = (name: string, message?: string) => void;
But this is not:
type GreetFunction = (name?: string, message: string) => void;
Default parameters
You can also assign default values to some parameters by using the
=
syntax. This means that these parameters will have the default values when they are not provided when calling the function. For example:
function sayHello(name = "stranger") {
console.log(`Hello, ${name}!`);
sayHello("Alice");
sayHello();
Note that default parameters are also considered optional by TypeScript, so you don’t need to add a
?
after their names. However, unlike optional parameters, default parameters can come before required parameters in a function type. For example:
type GreetFunction = (name = "stranger", message: string) => void;
Nullable types
You can use union types to express that a parameter can have more than one possible type. For example, you can use the
|
symbol to indicate that a parameter can be either a
string
or a
number
:
type StringOrNumber = string | number;
function print(value: StringOrNumber) {
console.log(value);
print("hello");
print(42);
print(true);
One common use case of union types is to allow a parameter to have a null or undefined value. For example, you can use the
|
symbol to indicate that a parameter can be either a
string
or
null
:
type NullableString = string | null;
function print(value: NullableString) {
if (value === null) {
console.log("No value");
} else {
console.log(value);
print("hello");
print(null);
print(undefined);
Similarly, you can use the
|
symbol to indicate that a parameter can be either a
string
or
undefined
:
type OptionalString = string | undefined;
function print(value: OptionalString) {
if (value === undefined) {
console.log("No value");
} else {
console.log(value);
print("hello");
print(undefined);
print(null);
You can also combine both
null
and
undefined
in a union type to allow both values:
type MaybeString = string | null | undefined;
function print(value: MaybeString) {
if (value == null) {
console.log("No value");
} else {
console.log(value);
print("hello");
print(null);
print(undefined);
Note that when using union types with
null
or
undefined
, you need to use type guards or type assertions to narrow down the possible types inside the function body. For example, you can use the
typeof
operator, the
===
operator, or the optional chaining operator (
?.
) to check for the presence of a value before accessing its properties or methods. For example:
type User = {
name: string;
age: number;
type MaybeUser = User | null | undefined;
function printUser(user: MaybeUser) {
if (typeof user === "object" && user !== null) {
console.log(`Name: ${user.name}, Age: ${user.age}`);
} else {
console.log("No user");
function printUserName(user: MaybeUser) {
if (user?.name) {
console.log(`Name: ${user.name}`);
} else {
console.log("No name");
Combining optional, default, and nullable types
By combining these features, you can create functions that can handle a wider range of input values, and ensure that your code is more resilient to unexpected input.
Note that when you combine optional and default parameters, the default value will be used when the argument is omitted or undefined, but not when it is null. If you want the default value to be used for both null and undefined, you can use the nullish coalescing operator (??) in the function body. For example:
function sayHello(name: string | null = "stranger") {
name = name ?? "stranger";
console.log(`Hello, ${name}!`);
sayHello("Alice");
sayHello(null);
sayHello();
However it’s invalid to declare a function parameter with both a question mark (?) and an initializer (=). For example: