Functions Flashcards
What are function type expressions and how do you use them in TypeScript?
Function type expressions are similar to arrow functions, defining the parameter types and return type.
// Basic function type expression type GreetFunction = (name: string) => string; const greet: GreetFunction = (name) => `Hello, ${name}`; // Multiple parameters type MathOperation = (x: number, y: number) => number; const add: MathOperation = (a, b) => a + b;
What are call signatures and how do they differ from type expressions?
Call signatures allow you to add properties to functions using object type syntax.
interface DescribableFunction { description: string; (someArg: number): boolean; }; function doSomething(fn: DescribableFunction) { console.log(fn.description); console.log(fn(6)); } // Implementation const myFunc: DescribableFunction = (n: number) => n > 5; myFunc.description = "Checks if number is greater than 5";
What are construct signatures and when would you use them?
Construct signatures define types that can be instantiated with ‘new’.
type SomeConstructor = { new (s: string): object; }; class Example { constructor(s: string) { console.log(s); } } function fn(ctor: SomeConstructor) { return new ctor("hello"); } // With both call and construct signatures interface CallAndConstruct { new (s: string): Date; (n?: number): Date; }
How do you write and use generic functions?
Generic functions allow you to work with multiple types while maintaining type safety.
function identity<T>(arg: T): T { return arg; } // Using arrow functions const identity2 = <T>(arg: T): T => arg; // Generic with constraints function firstItem<T>(arr: T[]): T | undefined { return arr[0]; } // Multiple type parameters function pair<T, U>(first: T, second: U): [T, U] { return [first, second]; }
How does type inference work with generics?
TypeScript can often infer generic types from usage context.
function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] { return arr.map(func); } // Type inference in action const numbers = [1, 2, 3]; const doubled = map(numbers, n => n * 2); // TypeScript infers number[] const strings = ["hello", "world"]; const lengths = map(strings, s => s.length); // TypeScript infers number[]
How do you use constraints with generic types?
Constraints limit what types can be used with generics using ‘extends’.
interface Lengthwise { length: number; } function logLength<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; } // Valid logLength("hello"); logLength([1, 2, 3]); logLength({ length: 10, value: 3 }); // Invalid - number doesn't have length // logLength(42); // Error!
How do you work effectively with constrained types?
You can access properties guaranteed by constraints.
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) { return obj[key]; } let obj = { a: 1, b: 2, c: 3 }; // Valid getProperty(obj, "a"); // Invalid // getProperty(obj, "z"); // Error: "z" is not in keyof Type
When do you need to specify type arguments explicitly?
Sometimes TypeScript needs help inferring types.
function create<T>(value: T): T[] { return [value]; } // Explicit type argument const stringArray = create<string>("hello"); // Complex example function combine<T>(arr1: T[], arr2: T[]): T[] { return [...arr1, ...arr2]; } // Need explicit type here const mixed = combine<string | number>([1, 2], ["a", "b"]);
How do you work with optional parameters?
Optional parameters are marked with ? and must come after required parameters.
function buildName(firstName: string, lastName?: string): string { if (lastName) { return `${firstName} ${lastName}`; } return firstName; } // Default parameters function greet(name = "World"): string { return `Hello, ${name}!`; }
How do you implement function overloads?
Function overloads allow multiple call signatures for a single function.
```typescript
function makeDate(timestamp: number): Date;
function makeDate(year: number, month: number, day: number): Date;
function makeDate(yearOrTimestamp: number, month?: number, day?: number): Date {
if (month !== undefined && day !== undefined) {
return new Date(yearOrTimestamp, month - 1, day);
}
return new Date(yearOrTimestamp);
}
// Usage
const d1 = makeDate(123456789);
const d2 = makeDate(2024, 1, 1);
~~~
How do you work with the object type in TypeScript?
The object type represents any non-primitive type.
```typescript
const obj: object = { x: 10, y: 20 };
// obj.x; // Error: Property ‘x’ does not exist on type ‘object’
// Better to use specific type
const point: { x: number; y: number } = { x: 10, y: 20 };
point.x; // OK
~~~
What is the unknown type and how is it used safely?
unknown represents any value but requires checking before use.
```typescript
function processValue(val: unknown): string {
if (typeof val === “string”) {
return val.toUpperCase();
}
if (typeof val === “number”) {
return val.toFixed(2);
}
throw new Error(“Invalid type”);
}
// Usage
let value: unknown = “hello”;
// value.toUpperCase(); // Error
if (typeof value === “string”) {
value.toUpperCase(); // OK
}
~~~
What is the never type and when is it used?
never represents values that never occur.
```typescript
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
// Exhaustive checking
type Shape = Circle | Square;
function assertNever(x: never): never {
throw new Error(“Unexpected object: “ + x);
}
~~~
How do you work with rest parameters and spread arguments?
Rest parameters collect multiple arguments into an array.
```typescript
// Rest parameters
function sum(…numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}
// Rest arguments
const numbers = [1, 2, 3];
console.log(sum(…numbers));
// Typing tuple rest parameters
function concat<T extends unknown[]>(…arrays: T[]): T[number][] {
return arrays.flat();
}
~~~
How do you use parameter destructuring with TypeScript?
Parameter destructuring lets you unpack objects or arrays in parameters.
```typescript
interface User {
name: string;
age: number;
}
function printUser({ name, age }: User) {
console.log(${name} is ${age} years old
);
}
// With defaults
function printUserWithDefaults({ name = “Anonymous”, age = 0 }: Partial<User> = {}) {
console.log(`${name} is ${age} years old`);
}
~~~</User>
What is the void return type and how does it work?
void indicates a function doesn’t return a value.
```typescript
function logMessage(msg: string): void {
console.log(msg);
}
// void vs undefined
function returnsVoid(): void {
return undefined; // OK
}
function returnsUndefined(): undefined {
return undefined; // OK
}
// Contextual typing with void
type VoidFunc = () => void;
const f1: VoidFunc = () => true; // OK - return value is ignored
~~~