Functions are a core concept in TypeScript, just as in JavaScript, but TypeScript enhances functions by providing static types and advanced type features like type inference, overloads, and more.
In this tutorial, we’ll cover TypeScript functions in depth and provide several examples to illustrate different aspects of function types.
1. Basic Function Syntax
In TypeScript, you can define functions similarly to how you would in JavaScript, but with optional type annotations for parameters and return types.
Example 1: Basic Function with Types
function add(x: number, y: number): number { return x + y; } console.log(add(2, 3)); // Output: 5
Here, x and y are parameters of type number, and the function is expected to return a value of type number. If you omit the return type, TypeScript infers it automatically based on the return value.
2. Function Parameters
You can explicitly define types for function parameters to ensure type safety, which is one of TypeScript’s key features.
Example 2: Function Parameter Types
function greet(name: string): string { return `Hello, ${name}!`; } console.log(greet("John")); // Output: Hello, John!
In this example, the greet function takes a single parameter name of type string and returns a string.
3. Optional and Default Parameters
TypeScript allows you to define optional and default parameters in functions. Optional parameters are denoted by a question mark ?, while default parameters are assigned default values.
Example 3: Optional and Default Parameters
function logMessage(message: string, user?: string): void { if (user) { console.log(`${user}: ${message}`); } else { console.log(message); } } function greetUser(name: string, greeting: string = "Hello"): string { return `${greeting}, ${name}`; } logMessage("Welcome"); // Output: Welcome logMessage("Welcome", "Alice"); // Output: Alice: Welcome console.log(greetUser("John")); // Output: Hello, John console.log(greetUser("John", "Welcome")); // Output: Welcome, John
Optional parameters: user? is optional in logMessage. If no value is provided, it will be undefined.
Default parameters: greeting in greetUser has a default value of “Hello”.
4. Return Types and Type Inference
You can explicitly specify the return type of a function, but TypeScript is smart enough to infer it based on the returned value.
Example 4: Return Types
function multiply(a: number, b: number): number { return a * b; } function log(message: string): void { console.log(message); } const result = multiply(5, 3); // TypeScript infers result to be of type 'number' log(result.toString()); // Output: 15
In the multiply function, the return type number is explicitly declared, but in many cases, TypeScript can infer the type. The log function has a return type of void because it doesn’t return a value.
5. Anonymous and Arrow Functions
TypeScript supports anonymous and arrow functions, just like JavaScript. You can use type annotations with these as well.
Example 5: Anonymous and Arrow Functions
const addNumbers = function (x: number, y: number): number { return x + y; }; const multiplyNumbers = (x: number, y: number): number => x * y; console.log(addNumbers(4, 5)); // Output: 9 console.log(multiplyNumbers(4, 5)); // Output:
Arrow functions provide a more concise syntax, especially for shorter functions.
6. Function Overloading
TypeScript allows function overloading, where multiple function signatures are declared, and a single implementation handles all of them. This is useful when a function can behave differently based on the type or number of arguments.
Example 6: Function Overloading
function getLength(value: string): number; function getLength(value: any[]): number; function getLength(value: string | any[]): number { return value.length; } console.log(getLength("Hello")); // Output: 5 console.log(getLength([1, 2, 3])); // Output: 3
In this example, the getLength function has two overloads: one for string and another for any[] (arrays). The implementation handles both cases.
7. Rest Parameters and Spread Syntax
TypeScript supports rest parameters, which allow you to pass an indefinite number of arguments into a function.
Example 7: Rest Parameters
function sumAll(...numbers: number[]): number { return numbers.reduce((sum, num) => sum + num, 0); } console.log(sumAll(1, 2, 3)); // Output: 6 console.log(sumAll(10, 20, 30)); // Output: 60
The …numbers syntax allows us to handle any number of arguments as an array within the function.
8. Function as a Type
In TypeScript, functions can also be treated as types. You can define a function type by specifying the types of the parameters and return value.
Example 8: Function as a Type
let mathOperation: (a: number, b: number) => number; mathOperation = function (x: number, y: number): number { return x + y; }; console.log(mathOperation(5, 10)); // Output: 15
In this example, mathOperation is a variable with a function type that takes two numbers as parameters and returns a number.
9. Generic Functions
Generic functions allow you to define functions that work with a variety of types, making your code more reusable and flexible.
Example 9: Generic Functions
function identity(arg: T): T { return arg; } console.log(identity(5)); // Output: 5 console.log(identity("Hi")); // Output: Hi
In this example, the identity function is a generic function where T represents any type passed to the function. When calling the function, you can specify the type explicitly, or TypeScript can infer it.
Conclusion
Functions in TypeScript are much more powerful and flexible than those in JavaScript due to TypeScript’s type system. With features like optional and default parameters, type inference, function overloading, and generics, you can write functions that are type-safe, clear, and reusable.
By understanding and utilizing these features, you can make your TypeScript code more robust and reduce the chances of runtime errors.