Type System & Type Manipulation Interview Questions
Comprehensive type system & type manipulation interview questions and answers for TypeScript. Prepare for your next job interview with expert guidance.
Questions Overview
1. What are mapped types in TypeScript?
Advanced2. Explain conditional types in TypeScript.
Advanced3. What is the keyof operator in TypeScript?
Moderate4. How do intersection types work in TypeScript?
Basic5. What is the typeof operator in TypeScript and how does it differ from JavaScript's typeof?
Moderate6. What are utility types in TypeScript and name some common ones.
Moderate7. How do you use the infer keyword in TypeScript?
Advanced8. What is type widening and narrowing in TypeScript?
Advanced9. How do you create type aliases in TypeScript?
Basic10. Explain index types and index signatures in TypeScript.
Moderate11. What is the purpose of the unknown type in TypeScript?
Moderate12. How do you use template literal types in TypeScript?
Advanced13. What are discriminated unions in TypeScript?
Moderate14. How do you use the Omit utility type?
Moderate15. What is the difference between type assertions and type declarations?
Basic16. How do you use the Pick utility type?
Moderate17. What are recursive types in TypeScript?
Advanced18. How do you use the ReturnType utility type?
Moderate19. What is the Readonly utility type and when should you use it?
Moderate20. How do you use lookup types in TypeScript?
Moderate21. What are literal type widening and const assertions?
Advanced22. How do you use the Extract utility type?
Advanced23. What is the difference between Record and index signatures?
Advanced1. What are mapped types in TypeScript?
AdvancedMapped types allow you to create new types based on existing ones by transforming each property in the same way. They use the syntax { [P in keyof T]: NewType }. Common examples include making all properties optional (Partial<T>), readonly (Readonly<T>), or nullable. This is powerful for type transformations and creating utility types.
2. Explain conditional types in TypeScript.
AdvancedConditional types select one of two possible types based on a condition expressed as a type relationship test. They use the syntax T extends U ? X : Y. They're powerful for creating complex type logic and are often used with generics. For example: type NonNullable<T> = T extends null | undefined ? never : T.
3. What is the keyof operator in TypeScript?
ModerateThe keyof operator takes an object type and produces a string or numeric literal union of its keys. It's useful for creating types that depend on the properties of other types. For example: type Point = { x: number; y: number }; type PointKey = keyof Point; // type PointKey = 'x' | 'y'
4. How do intersection types work in TypeScript?
BasicIntersection types combine multiple types into one using the & operator. The resulting type has all properties from all the constituent types. For example: type Employee = Person & { employeeId: number }. This creates a new type that must satisfy all the requirements of both Person and the object with employeeId.
5. What is the typeof operator in TypeScript and how does it differ from JavaScript's typeof?
ModerateTypeScript's typeof operator can be used in type contexts to reference the type of a variable or property. Unlike JavaScript's typeof which returns a string at runtime, TypeScript's typeof is used in type positions to create type references. Example: const point = { x: 0, y: 0 }; type Point = typeof point; // creates a type with shape { x: number, y: number }
6. What are utility types in TypeScript and name some common ones.
ModerateUtility types are built-in types that facilitate common type transformations. Common utility types include: Partial<T> (makes all properties optional), Required<T> (makes all properties required), Readonly<T> (makes all properties readonly), Pick<T,K> (constructs type with subset of properties), Record<K,T> (constructs type with properties of keys K and type T), Exclude<T,U>, and Extract<T,U>.
7. How do you use the infer keyword in TypeScript?
AdvancedThe infer keyword is used in conditional types to extract and infer type parameters from other types. It's commonly used for complex type manipulations and for extracting types from functions, promises, and arrays. Example: type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any; This extracts the return type of a function type.
8. What is type widening and narrowing in TypeScript?
AdvancedType widening is when TypeScript expands a narrow type to a more general one (like expanding a literal type to its base type). Type narrowing is the opposite - restricting a type to a more specific one through control flow analysis, type guards, or assertions. Understanding these concepts is crucial for working with TypeScript's type system effectively.
9. How do you create type aliases in TypeScript?
BasicType aliases are created using the type keyword followed by a name and type definition. They can represent simple types, unions, intersections, tuples, or complex object types. Example: type Point = { x: number; y: number }; type ID = string | number; They provide a way to give meaningful names to types and reduce repetition.
10. Explain index types and index signatures in TypeScript.
ModerateIndex types allow you to create objects with dynamic property names while maintaining type safety. Index signatures use the syntax [key: string]: ValueType to specify that an object can have any number of properties with names of type string (or number) and values of ValueType. Example: type Dictionary = { [key: string]: string }; This allows any string keys with string values.
11. What is the purpose of the unknown type in TypeScript?
ModerateThe unknown type is a type-safe alternative to any. While any allows all operations without type checking, unknown requires type checking or assertion before operations can be performed. This makes unknown safer than any because it forces you to perform type checks before using the value. It's ideal for representing values whose type you don't know at compile time.
12. How do you use template literal types in TypeScript?
AdvancedTemplate literal types combine literal types through template literal strings. They allow creating new string literal types by concatenating existing ones. Example: type EmailLocale = 'en' | 'fr' | 'de'; type EmailType = 'welcome' | 'goodbye'; type EmailTemplate = `${EmailLocale}_${EmailType}`; // Creates types like 'en_welcome', 'fr_goodbye', etc.
13. What are discriminated unions in TypeScript?
ModerateDiscriminated unions are union types where each member has a common property (the discriminant) that TypeScript can use to narrow down the specific type. Example: type Shape = { kind: 'circle'; radius: number } | { kind: 'square'; sideLength: number }. The 'kind' property helps TypeScript determine which shape type is being used.
14. How do you use the Omit utility type?
ModerateOmit<T, K> constructs a type by picking all properties from T and then removing those in K. It's useful for creating new types that exclude certain properties. Example: type Person = { name: string; age: number; email: string }; type PersonWithoutEmail = Omit<Person, 'email'>; // Results in { name: string; age: number }
15. What is the difference between type assertions and type declarations?
BasicType assertions tell TypeScript to treat a value as a specific type using 'as' or angle bracket syntax. Type declarations explicitly define the type using ':'. Assertions are used when you know more about a type than TypeScript can infer, while declarations are used to specify what type a variable should have. Example: let str1 = value as string; (assertion) vs let str2: string = value; (declaration)
16. How do you use the Pick utility type?
ModeratePick<T, K> constructs a type by picking a set of properties K from type T. It's useful when you want to create a new type with only specific properties from an existing type. Example: type Person = { name: string; age: number; address: string }; type NameAge = Pick<Person, 'name' | 'age'>; // Results in { name: string; age: number }
17. What are recursive types in TypeScript?
AdvancedRecursive types are types that reference themselves in their definition. They're useful for representing tree-like data structures or nested objects. Example: type TreeNode<T> = { value: T; children?: TreeNode<T>[] }; This creates a type that can represent a tree structure where each node can have child nodes of the same type.
18. How do you use the ReturnType utility type?
ModerateReturnType<T> extracts the return type of a function type T. It's useful when you want to reference the return type of a function without explicitly defining it. Example: function createUser() { return { id: 1, name: 'John' } }; type User = ReturnType<typeof createUser>; // Type will be { id: number; name: string }
19. What is the Readonly utility type and when should you use it?
ModerateReadonly<T> creates a new type where all properties of T are readonly. It's useful when you want to ensure that properties can't be modified after initialization. Example: type Point = { x: number; y: number }; type ReadonlyPoint = Readonly<Point>; This prevents accidental mutations of object properties.
20. How do you use lookup types in TypeScript?
ModerateLookup types allow you to extract the type of a property from another type using indexed access notation. Example: type Person = { age: number; name: string }; type AgeType = Person['age']; // type AgeType = number. This is useful when you need to reference the type of a specific property from an existing type.
21. What are literal type widening and const assertions?
AdvancedLiteral type widening occurs when TypeScript widens a literal type to its base type. Const assertions (using 'as const') prevent this widening and create readonly literal types. Example: let x = 'hello' // type is string (widened), but let x = 'hello' as const // type is 'hello' (literal). Const assertions are useful for creating precise literal types.
22. How do you use the Extract utility type?
AdvancedExtract<T, U> extracts from T all types that are assignable to U. It's useful for filtering union types. Example: type Numbers = Extract<string | number | boolean, number>; // Results in type Numbers = number. This utility helps create new types by filtering existing union types based on assignability.
23. What is the difference between Record and index signatures?
AdvancedRecord<K,T> creates an object type with properties of type K and values of type T, while index signatures use [key: K]: T syntax. Record is more strict as it requires all keys to exist, while index signatures allow any key. Example: type StringMap = Record<string, string> vs type StringDict = { [key: string]: string }.