TypeScript Data Analysis & Reporting 5 β Questions and Answers
Question 1: In TypeScript, how would you type a generic data filter function that takes a predicate and returns only the matching elements with the correct narrowed type?
- function filter(arr: any[], pred: Function): any[]
- function filter<T, U extends T>(arr: T[], pred: (item: T) => item is U): U[] (Correct answer)
- function filter<T>(arr: T[], pred: boolean): T[]
- function filter(arr: unknown[]): unknown[]
Correct answer: function filter<T, U extends T>(arr: T[], pred: (item: T) => item is U): U[]
Using a type predicate '(item: T) => item is U' causes the returned array to be typed as U[], reflecting the narrowed type after filtering.
Question 2: A report dashboard needs to display data from three different API endpoints with different shapes. Which TypeScript pattern helps you normalize them into a single unified type?
- Cast all responses to 'any' and merge
- Define a union type and use type guards to normalize each shape into a common interface (Correct answer)
- Use Object.assign with no type annotation
- Stringify all responses and reparse
Correct answer: Define a union type and use type guards to normalize each shape into a common interface
A union type with type guards allows TypeScript to understand each variant's shape so you can safely extract and normalize fields into the common interface.
Question 3: What does the TypeScript 'infer' keyword enable when used in conditional types for data analysis utilities?
- It forces TypeScript to skip type checking
- It extracts and names a type from within another type during conditional type evaluation (Correct answer)
- It converts runtime values to types
- It replaces generics entirely
Correct answer: It extracts and names a type from within another type during conditional type evaluation
The 'infer' keyword captures a type variable during pattern matching within conditional types, allowing utilities like ReturnType<T> to extract inner types.
Question 4: You need to deep-freeze a report configuration object at runtime and reflect that immutability in the TypeScript type. Which approach achieves both goals?
- Cast with 'as Readonly<Config>'
- Use Object.freeze() and type the return as DeepReadonly<Config> (Correct answer)
- Use 'const' keyword only
- Return 'undefined' for disallowed mutations
Correct answer: Use Object.freeze() and type the return as DeepReadonly<Config>
Object.freeze() prevents runtime mutations while DeepReadonly<Config> (a recursive mapped type) reflects that immutability at the type level for nested objects.
Question 5: When integrating a third-party charting library with no TypeScript definitions, what is the safest way to type its data input in your TypeScript data layer?
- Pass data directly with no type annotation
- Write a custom .d.ts file with at least the input shape you use, or use DefinitelyTyped (Correct answer)
- Cast chart data to 'any' everywhere it's passed
- Avoid TypeScript in that file
Correct answer: Write a custom .d.ts file with at least the input shape you use, or use DefinitelyTyped
Writing a minimal .d.ts declaration for the portion of the library you use provides type safety at the integration boundary without requiring a full type definition.
Question 6: In TypeScript, which approach correctly types a function that accepts a dynamic column name and returns the value of that column from a row object?
- function getField(row: object, col: string): any
- function getField<T, K extends keyof T>(row: T, col: K): T[K] (Correct answer)
- function getField(row: any, col: any): any
- function getField<T>(row: T, col: string): unknown
Correct answer: function getField<T, K extends keyof T>(row: T, col: K): T[K]
Using K extends keyof T and T[K] as the return type ensures the returned value's type matches exactly the type of the accessed property.
Question 7: What TypeScript feature would you use to ensure a report configuration object always has exactly the properties defined by its interface, with no extra properties allowed at assignment?
- Type assertions bypass excess property checks
- Object literal assignments trigger excess property checking automatically (Correct answer)
- Use 'Partial<T>' to allow any shape
- Spread operators bypass property checks
Correct answer: Object literal assignments trigger excess property checking automatically
TypeScript applies excess property checking when you assign an object literal directly to a typed variable, catching any extra properties not in the interface.
In TypeScript, how would you type a generic data filter function that takes a predicate and returns only the matching elements with the correct narrowed type?