Functions

Change Topic
  • Function definition with arguments and a return type - how to pass arguments to a function and express the return type.
  • Function overloading - how to provide multiple different implementations with different sets of arguments
  • Default or Optional Arguments - how to provide defaults or express optionality in arguments
  • Lambda Functions - defining a lambda function
  • Lambda Function Capture - using local in-scope variables inside the lambda function
  • Function Type Parameter (Generics) - how to define a function with one or more types as an argument
  • Function Type Parameter Constraints - how to define a constraint on the type parameter

TypeScript Functions

Python Language


Function Definition with Arguments and Return Type

TypeScript allows specifying argument types and return types explicitly in function definitions.

function add(x: number, y: number): number { return x + y; } const greet = (name: string): string => `Hello, ${name}!`;
  • x: number, y: number: Defines parameter types.
  • : number after () specifies the return type.

Function Definition with Arguments and Return Type

Python allows function definitions with optional type hints for parameters and return values.

def add(x: int, y: int) -> int: return x + y def greet(name: str) -> str: return f"Hello, {name}!"
  • x: int, y: int - Type hints for parameters.
  • -> int - Type hint for return value.
  • Type hints are optional; Python does not enforce them at runtime.

Function Overloading

Function overloading processed at runtime

function add(x: number, y: number): number; function add(x: string, y: string): string; function add(x: any, y: any): any { return x + y; } console.log(add(5, 10)); // 15 console.log(add("Hello, ", "World!")); // "Hello, World!"

Function Overloading

Function overloading not supported explicitly, process at runtime:

def add(x, y=None): if y is None: # Single argument case return x return x + y print(add(5, 10)) # 15 print(add(5)) # 5

Or using Union:

from typing import Union def add(x: Union[int, str], y: Union[int, str]) -> Union[int, str]: return x + y print(add(5, 10)) # 15 print(add("Hello, ", "World!")) # "Hello, World!"

Or using @singledispatch:

from functools import singledispatch @singledispatch def process(value): raise NotImplementedError("Unsupported type") @process.register def _(value: int): return f"Processing an integer: {value}" @process.register def _(value: str): return f"Processing a string: {value}" print(process(42)) # "Processing an integer: 42" print(process("Hello")) # "Processing a string: Hello"

Function Default Arguments

function doIt(b: number, a = 1) { return b / a; } console.log("DoIt " + doIt(10) + " " + doIt(10, 2));

Function Default Arguments

def greet(name="World"): print(f"Hello, {name}!") greet() # Hello, World! greet("Alice") # Hello, Alice!

Lambda Functions

const doIt = (b: number, c: number) => a * b; console.log("DoIt " + doIt(10, 5));

Lambda Functions

add = lambda x, y: x + y print(add(3, 4)) # 7

There are some limitations:

  • Only one expression, no statements like if, for, print.
  • Can hurt readability for anything non-trivial.
  • Can't contain annotations or docstrings.

Lambda Function Capture

function createCounter(): () => number { let count = 0; // This variable is captured by the closure return () => { count += 1; return count; }; } const counterA = createCounter(); console.log(counterA()); // 1 console.log(counterA()); // 2 const counterB = createCounter(); console.log(counterB()); // 1 (separate closure) console.log(counterA()); // 3 (original closure still intact)
function makeMultiplier(factor: number): (input: number) => number { // factor is captured by the inner function return (input: number) => input * factor; } const double = makeMultiplier(2); const triple = makeMultiplier(3); console.log(double(5)); // 10 console.log(triple(5)); // 15

Lambda Functions With Capture

Supported...

x = 10 f = lambda: x + 1 print(f()) # 11 x = 20 print(f()) # 21 — uses the updated value of x

But note the following:

funcs = [lambda: i for i in range(3)] print([f() for f in funcs]) # [2, 2, 2] — not [0, 1, 2] # fix by binding i as a default argument for each iteration funcs = [lambda i=i: i for i in range(3)] print([f() for f in funcs]) # [0, 1, 2]

Function Generics

function identity<T>(value: T): T { return value; } console.log(identity<number>(42)); // 42 console.log(identity<string>("Hello")); // "Hello"

Function Generics

from typing import TypeVar T = TypeVar('T') # Generic type placeholder def identity(value: T) -> T: return value print(identity(42)) # 42 print(identity("Hello")) # "Hello"

Function Generics Constraint

And with a constraint:

function getLength<T extends { length: number }>(arg: T): number { return arg.length; } console.log(getLength("Hello")); // 5 console.log(getLength([1, 2, 3])); // 3

Function Generics with Constraint

With a constraint:

from typing import TypeVar, Protocol class HasLength(Protocol): def __len__(self) -> int: ... T = TypeVar('T', bound=HasLength) def get_length(value: T) -> int: return len(value) print(get_length("Hello")) # 5 print(get_length([1, 2, 3])) # 3