TypeScript Interview Questions Your Guide to Success

TypeScript, a strongly typed superset of JavaScript, is essential for building scalable applications, making it a crucial skill for frontend developers, full-stack engineers, and software architects. Stark.ai offers a curated collection of TypeScript interview questions, real-world scenarios, and expert guidance to help you excel in your next technical interview.

Back

typescript

    • What is TypeScript and how does it differ from JavaScript?

      TypeScript is a strongly typed, object-oriented programming language that builds on JavaScript. It is a superset of...

    • What are the basic data types in TypeScript?

      TypeScript includes several basic data types: number (for both integers and floating-point values), string (for...

    • How do you declare variables with type annotations in TypeScript?

      In TypeScript, variables can be declared with type annotations using the colon (:) syntax. For example: 'let name:...

    • What is type inference in TypeScript?

      Type inference is TypeScript's ability to automatically determine types of variables based on their values and...

    • Explain the 'any' type in TypeScript and when should it be used?

      The 'any' type is a dynamic type that can hold values of any type. It effectively opts out of type checking for that...

    • What is the difference between 'interface' and 'type' in TypeScript?

      Both interface and type are used to define custom types, but they have some differences. Interfaces are extensible...

    • How does TypeScript handle null and undefined?

      TypeScript treats null and undefined as distinct types. By default, with strict null checks enabled...

    • What are literal types in TypeScript?

      Literal types are specific value types in TypeScript where you can specify the exact value a variable can have. For...

    • Explain type assertions in TypeScript and when to use them.

      Type assertions are a way to tell the TypeScript compiler that you know better about the type of a value. They can...

    • What is the 'never' type in TypeScript and when is it used?

      The 'never' type represents values that never occur. It is used for functions that never return (throw an error or...

    • How do you work with arrays in TypeScript?

      Arrays in TypeScript can be typed in two ways: using the type followed by [] (e.g., 'number[]') or using the generic...

    • What are union types in TypeScript?

      Union types allow a variable to hold values of multiple types. They are created using the | operator. For example:...

    • Explain the concept of type narrowing in TypeScript.

      Type narrowing is the process of refining types to more specific ones based on type guards and conditional checks....

    • What are type guards in TypeScript?

      Type guards are expressions that perform runtime checks to guarantee the type of a value in a scope. They can be...

    • How do you use enums in TypeScript?

      Enums allow defining a set of named numeric constants. There are numeric enums (default values auto-increment from...

    • What are mapped types in TypeScript?

      Mapped types allow you to create new types based on existing ones by transforming each property in the same way....

    • Explain conditional types in TypeScript.

      Conditional types select one of two possible types based on a condition expressed as a type relationship test. They...

    • What is the keyof operator in TypeScript?

      The keyof operator takes an object type and produces a string or numeric literal union of its keys. It's useful for...

    • How do intersection types work in TypeScript?

      Intersection types combine multiple types into one using the & operator. The resulting type has all properties from...

    • What is the typeof operator in TypeScript and how does it differ from JavaScript's typeof?

      TypeScript's typeof operator can be used in type contexts to reference the type of a variable or property. Unlike...

    • What are utility types in TypeScript and name some common ones.

      Utility types are built-in types that facilitate common type transformations. Common utility types include:...

    • How do you use the infer keyword in TypeScript?

      The infer keyword is used in conditional types to extract and infer type parameters from other types. It's commonly...

    • What is type widening and narrowing in TypeScript?

      Type widening is when TypeScript expands a narrow type to a more general one (like expanding a literal type to its...

    • How do you create type aliases in TypeScript?

      Type aliases are created using the type keyword followed by a name and type definition. They can represent simple...

    • Explain index types and index signatures in TypeScript.

      Index types allow you to create objects with dynamic property names while maintaining type safety. Index signatures...

    • What is the purpose of the unknown type in TypeScript?

      The unknown type is a type-safe alternative to any. While any allows all operations without type checking, unknown...

    • How do you use template literal types in TypeScript?

      Template literal types combine literal types through template literal strings. They allow creating new string...

    • What are discriminated unions in TypeScript?

      Discriminated unions are union types where each member has a common property (the discriminant) that TypeScript can...

    • How do you use the Omit utility type?

      Omit<T, K> constructs a type by picking all properties from T and then removing those in K. It's useful for creating...

    • What is the difference between type assertions and type declarations?

      Type assertions tell TypeScript to treat a value as a specific type using 'as' or angle bracket syntax. Type...

    • How do you use the Pick utility type?

      Pick<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...

    • What are recursive types in TypeScript?

      Recursive types are types that reference themselves in their definition. They're useful for representing tree-like...

    • How do you use the ReturnType utility type?

      ReturnType<T> extracts the return type of a function type T. It's useful when you want to reference the return type...

    • What is the Readonly utility type and when should you use it?

      Readonly<T> creates a new type where all properties of T are readonly. It's useful when you want to ensure that...

    • How do you use lookup types in TypeScript?

      Lookup types allow you to extract the type of a property from another type using indexed access notation. Example:...

    • What are literal type widening and const assertions?

      Literal type widening occurs when TypeScript widens a literal type to its base type. Const assertions (using 'as...

    • How do you use the Extract utility type?

      Extract<T, U> extracts from T all types that are assignable to U. It's useful for filtering union types. Example:...

    • What is the difference between Record and index signatures?

      Record<K,T> creates an object type with properties of type K and values of type T, while index signatures use [key:...

    • What are classes in TypeScript and how do they differ from JavaScript classes?

      TypeScript classes are blueprints for creating objects that extend JavaScript classes with additional features like...

    • Explain access modifiers in TypeScript classes.

      TypeScript supports three access modifiers: public (default, accessible everywhere), private (only within the...

    • What are abstract classes in TypeScript?

      Abstract classes are base classes that cannot be instantiated directly and may contain abstract methods that must be...

    • How does inheritance work in TypeScript?

      TypeScript supports single inheritance using the 'extends' keyword. A class can inherit properties and methods from...

    • What are parameter properties in TypeScript?

      Parameter properties are a TypeScript shorthand that allows you to both declare and initialize class members in the...

    • How do you implement interfaces in TypeScript classes?

      Classes can implement interfaces using the 'implements' keyword. The class must provide implementations for all...

    • What are static members in TypeScript classes?

      Static members (properties and methods) belong to the class itself rather than instances of the class. They're...

    • How do you use getters and setters in TypeScript?

      TypeScript supports JavaScript's get and set accessors with additional type safety. They allow you to add logic when...

    • What is method overriding in TypeScript?

      Method overriding allows a subclass to provide a specific implementation of a method that is already defined in its...

    • How do you implement polymorphism in TypeScript?

      Polymorphism in TypeScript can be achieved through method overriding and interfaces. It allows objects of different...

    • What are private constructors and what are they used for?

      Private constructors prevent class instantiation from outside the class. They're commonly used in singleton pattern...

    • How do you implement the Singleton pattern in TypeScript?

      Singleton pattern ensures a class has only one instance. In TypeScript, it's implemented using a private constructor...

    • What is the 'readonly' modifier and how is it used in classes?

      The 'readonly' modifier makes class properties immutable after initialization. They must be initialized at...

    • How do you handle method overloading in TypeScript?

      TypeScript supports method overloading through function declarations with different parameter types or numbers....

    • What are abstract methods and when should you use them?

      Abstract methods are methods declared in abstract classes without implementation. They must be implemented by...

    • How do you implement the Factory pattern in TypeScript?

      The Factory pattern provides an interface for creating objects without specifying exact classes. In TypeScript, it's...

    • What is the protected constructor pattern?

      Protected constructors allow instantiation only from within the class itself or its derived classes. This pattern is...

    • How do you implement mixins in TypeScript?

      Mixins are a way to combine multiple classes into one. TypeScript implements mixins using class expressions and a...

    • What are index signatures in classes?

      Index signatures in classes allow you to define dynamic properties with a specific type. They're defined using [key:...

    • How do you implement the Observer pattern in TypeScript?

      The Observer pattern is implemented using interfaces for Subject and Observer, with the Subject maintaining a list...

    • What is the difference between composition and inheritance in TypeScript?

      Composition involves creating complex objects by combining simpler ones, while inheritance creates relationships...

    • How do you use the 'super' keyword in TypeScript?

      The 'super' keyword is used to call methods or access properties on the parent class. It's commonly used in...

    • What are type guards in class hierarchies?

      Type guards in class hierarchies help narrow down types when working with inheritance. The instanceof operator is...

    • What are the different ways to define function types in TypeScript?

      TypeScript offers several ways to define function types: 1) Using interface: interface Func { (x: number): number;...

    • How do optional parameters work in TypeScript functions?

      Optional parameters are marked with a '?' after the parameter name. They must come after required parameters....

    • What are rest parameters in TypeScript functions?

      Rest parameters allow functions to accept an indefinite number of arguments as an array. They're denoted by '...'...

    • How do you implement function overloading in TypeScript?

      Function overloading involves declaring multiple function signatures followed by a single implementation that...

    • What are generic functions in TypeScript?

      Generic functions allow creating reusable functions that can work with multiple types while maintaining type safety....

    • How do default parameters work in TypeScript?

      Default parameters provide fallback values for parameters that are not passed to the function. Example: function...

    • What are arrow functions in TypeScript and how do they differ from regular functions?

      Arrow functions provide a concise syntax for function expressions and lexically bind 'this'. Example: let add = (a:...

    • How do you type 'this' in function parameters?

      TypeScript allows typing 'this' parameter as the first parameter in function declarations. Example: function...

    • What are higher-order functions in TypeScript?

      Higher-order functions are functions that take other functions as parameters or return functions. Example: function...

    • How do you type callbacks in TypeScript?

      Callbacks can be typed using function types or interfaces. Example: interface Callback { (error: Error | null,...

    • What are function type assertions?

      Function type assertions allow you to tell TypeScript that a function is of a specific type. Example: const myFunc =...

    • How do you implement currying in TypeScript?

      Currying transforms a function with multiple arguments into a sequence of functions, each taking a single argument....

    • What are function type intersections?

      Function type intersections combine multiple function types into one that must satisfy all types. Example: type...

    • How do you type async functions in TypeScript?

      Async functions are typed with Promise<T> where T is the type of the resolved value. Example: async function...

    • What are generator functions in TypeScript?

      Generator functions return iterables using the function* syntax and yield keyword. Example: function* range(start:...

    • How do you implement method chaining in TypeScript?

      Method chaining involves returning this from methods to enable consecutive calls. Example: class Calculator {...

    • What are function type unions?

      Function type unions allow a function to have multiple possible types. Example: type StringOrNumberFunc = ((x:...

    • How do you type function decorators?

      Function decorators are typed as functions that take a function descriptor and return a new descriptor or value....

    • What is function type inference in TypeScript?

      TypeScript can infer function return types and sometimes parameter types based on usage and context. Example:...

    • How do you implement function composition in TypeScript?

      Function composition combines multiple functions into a single function, applying them in sequence. Example: const...

    • What are contextual typing and how does it work with functions?

      Contextual typing allows TypeScript to infer types based on the context where a function is used. Example: const...

    • How do you type event handlers in TypeScript?

      Event handlers are typically typed using the appropriate event interface. Example: function handleClick(event:...

    • What are call signatures and construct signatures?

      Call signatures define how a function can be called, while construct signatures define how a function can be used...

    • How do you type function properties?

      Function properties are typed using regular property syntax on function types. Example: interface FunctionWithProps...

    • What are function type constraints in generics?

      Function type constraints limit what types can be used with generic functions. Example: function longest<T extends {...

    • What are generics in TypeScript and why are they useful?

      Generics are a way to create reusable components that can work with multiple types while maintaining type safety....

    • How do you use generic constraints in TypeScript?

      Generic constraints limit what types can be used with a generic type using the 'extends' keyword. Example: function...

    • What are generic interfaces and how do you implement them?

      Generic interfaces are interfaces that can work with multiple types. Example: interface Container<T> { value: T;...

    • What are conditional types in TypeScript?

      Conditional types select a type based on a condition, using syntax similar to ternary operators: T extends U ? X :...

    • How do you use generic type inference?

      TypeScript can infer generic types from usage context. Example: function identity<T>(arg: T): T { return arg; } let...

    • What are type parameters in generics?

      Type parameters are placeholders for types in generic definitions, conventionally denoted by T, U, K, V, etc....

    • How do you use generic classes in TypeScript?

      Generic classes use type parameters to create flexible, reusable class definitions. Example: class Stack<T> {...

    • What are mapped types and how do they work?

      Mapped types create new types by transforming properties of existing types. Example: type Readonly<T> = { readonly...

    • How do you use the infer keyword in conditional types?

      The infer keyword extracts type information within conditional types. Example: type ReturnType<T> = T extends...

    • What are generic type defaults?

      Generic type defaults provide fallback types when no type argument is specified. Example: interface Container<T =...

    • How do you use multiple type parameters in generics?

      Multiple type parameters allow generics to work with multiple types simultaneously. Example: function pair<T,...

    • What are index types and how do they work with generics?

      Index types allow type-safe access to properties using dynamic keys. Example: function getProperty<T, K extends...

    • How do you create generic type guards?

      Generic type guards combine generics with type predicates. Example: function isOfType<T>(value: any, property: keyof...

    • What are union and intersection types in generics?

      Union and intersection types can be used with generics to create flexible type combinations. Example: function...

    • How do you use generic type aliases?

      Generic type aliases create reusable type definitions with type parameters. Example: type Result<T> = { success:...

    • How do you use generic constraints with unions and intersections?

      Generic constraints can use union and intersection types to create complex type requirements. Example: function...

    • What are branded types and how do they work with generics?

      Branded types are nominal types created using intersection with unique symbols. Example: type Brand<T, B> = T & {...

    • How do you use keyof with generics?

      The keyof operator can be used with generics to create type-safe property access. Example: function...

    • What are variadic tuple types?

      Variadic tuple types allow working with tuples of variable length in a type-safe way. Example: type Concat<T extends...

    • How do you use template literal types with generics?

      Template literal types can be combined with generics to create dynamic string types. Example: type PropEventType<T...

    • What are generic type assertions?

      Generic type assertions allow specifying type parameters when using type assertions. Example: function...

    • How do you use generic default types with constraints?

      Generic default types can be combined with constraints to provide flexible yet safe defaults. Example: interface...

    • What are distributive conditional types?

      Distributive conditional types apply conditions to each member of a union type. Example: type ToArray<T> = T extends...

    • How do you create type-safe event emitters with generics?

      Generic event emitters provide type safety for event handling. Example: class EventEmitter<Events extends...

    • What is the difference between interfaces and type aliases in TypeScript?

      Key differences include: 1) Interfaces are extendable through declaration merging while type aliases are not, 2)...

    • How does interface inheritance work in TypeScript?

      Interfaces can inherit from other interfaces using the 'extends' keyword. They can extend multiple interfaces,...

    • What are optional properties in interfaces?

      Optional properties in interfaces are marked with a '?' symbol after the property name. They don't need to be...

    • How do you implement readonly properties in interfaces?

      Readonly properties are marked with the 'readonly' modifier and cannot be changed after initialization. Example:...

    • What are index signatures in interfaces?

      Index signatures allow interfaces to describe objects with dynamic property names. Example: interface StringMap {...

    • How do you define function types in interfaces?

      Function types in interfaces can be defined using call signatures. Example: interface Calculation { (x: number, y:...

    • What is declaration merging with interfaces?

      Declaration merging allows multiple interface declarations with the same name to be automatically combined. Example:...

    • How do you use generics with interfaces?

      Interfaces can use generic type parameters to create flexible, reusable definitions. Example: interface Container<T>...

    • What are hybrid types in interfaces?

      Hybrid types combine function types with object properties. Example: interface Counter { (start: number): string;...

    • How do you extend multiple interfaces?

      An interface can extend multiple interfaces using comma-separated names. Example: interface Shape { color: string; }...

    • What are recursive types in interfaces?

      Recursive types are interfaces that reference themselves in their definition. Example: interface TreeNode { value:...

    • How do you use mapped types with interfaces?

      Mapped types can be used to transform interface properties systematically. Example: type Readonly<T> = { readonly [P...

    • What are utility types for interfaces?

      Utility types provide common type transformations for interfaces. Example: interface User { name: string; age?:...

    • How do you implement method overloading in interfaces?

      Method overloading in interfaces is achieved by declaring multiple function signatures. Example: interface Document...

    • What are union and intersection types with interfaces?

      Union types (|) allow a value to be one of several types, while intersection types (&) combine multiple types....

    • How do you use type guards with interfaces?

      Type guards help narrow down interface types in conditional blocks. Example: interface Bird { fly(): void; }...

    • What are computed properties in interfaces?

      Computed properties allow property names to be expressions. Example: type Events = 'click' | 'focus'; interface...

    • How do you use interfaces with classes?

      Classes can implement interfaces using the 'implements' keyword. Example: interface Printable { print(): void; }...

    • What are literal types in interfaces?

      Literal types specify exact values that a property must have. Example: interface Config { mode: 'development' |...

    • How do you use interfaces with generics constraints?

      Interfaces can be used as constraints for generic types. Example: interface Lengthwise { length: number; } function...

    • What are optional methods in interfaces?

      Optional methods in interfaces are marked with '?' and don't need to be implemented. Example: interface Logger {...

    • How do you use interfaces with array types?

      Interfaces can describe array-like structures using index signatures or extending Array. Example: interface...

    • What are constructor signatures in interfaces?

      Constructor signatures define how a class constructor should look. Example: interface ClockConstructor { new (hour:...

    • How do you use interfaces with function overloading?

      Interfaces can define multiple call signatures for function overloading. Example: interface StringNumberFunction {...

    • What are static properties in interfaces?

      Interfaces can define static members that must be implemented by the class itself rather than instances. Example:...

    • What are ES modules in TypeScript and how do they differ from namespaces?

      ES modules are the standard JavaScript module system that TypeScript supports. They use import/export syntax and...

    • How do you use export and import statements in TypeScript?

      TypeScript supports various export/import syntaxes: 1) Named exports: export { MyClass }; 2) Default exports: export...

    • What are namespaces in TypeScript and when should you use them?

      Namespaces (formerly 'internal modules') are TypeScript's own module system for encapsulating code. They use the...

    • How do you use barrel exports in TypeScript?

      Barrel exports consolidate multiple exports into a single entry point using an index.ts file. Example: export * from...

    • What is module augmentation in TypeScript?

      Module augmentation allows you to add new declarations to existing modules. Example: declare module 'lodash' {...

    • How do you handle circular dependencies in TypeScript modules?

      Circular dependencies occur when two modules import each other. They can be resolved by: 1) Restructuring code to...

    • What are ambient modules in TypeScript?

      Ambient modules declare types for JavaScript modules that don't have TypeScript declarations. They use declare...

    • How do you use namespace merging in TypeScript?

      Namespace merging allows combining multiple namespace declarations with the same name. Example: namespace Animals {...

    • What are the different module resolution strategies in TypeScript?

      TypeScript supports several module resolution strategies: 1) Classic: Legacy resolution for AMD/System.js, 2) Node:...

    • How do you use dynamic imports in TypeScript?

      Dynamic imports allow loading modules on demand using import() syntax. Example: async function loadModule() { const...

    • What are declaration files (.d.ts) and how do they work with modules?

      Declaration files (.d.ts) contain type information for JavaScript modules. They define the shape of modules without...

    • How do you use re-exports in TypeScript modules?

      Re-exports allow you to export items from other modules. Syntax includes: export { Something } from './other',...

    • What are the best practices for organizing modules in TypeScript?

      Best practices include: 1) One class/feature per file, 2) Use barrel exports (index.ts) for related features, 3)...

    • How do you handle module path aliases in TypeScript?

      Module path aliases are configured in tsconfig.json using the paths option. Example: { 'compilerOptions': {...

    • What is the difference between internal and external modules?

      Internal modules (namespaces) use the namespace keyword and are TypeScript-specific. External modules (ES modules)...

    • How do you use namespace exports and imports?

      Namespaces use export keyword for public members and can be accessed using dot notation. Example: namespace Math {...

    • What are synthetic default imports in TypeScript?

      Synthetic default imports allow importing modules that don't have explicit default exports as if they did....

    • How do you handle module side effects in TypeScript?

      Module side effects are handled using import statements without bindings. Example: import './polyfills'; This...

    • What are global modules in TypeScript?

      Global modules are ambient modules that add types to the global scope. Example: declare global { interface Window {...

    • How do you use type-only imports and exports?

      Type-only imports/exports are used for importing/exporting types without value emissions. Syntax: import type {...

    • What are the patterns for lazy loading modules in TypeScript?

      Lazy loading patterns include: 1) Dynamic imports: import('./module'), 2) Route-based splitting: loadChildren in...

    • How do you handle module resolution in monorepos?

      Monorepo module resolution involves: 1) Using project references in tsconfig.json, 2) Configuring path aliases for...

    • What are the different ways to handle module augmentation?

      Module augmentation can be done through: 1) Declaration merging: declare module 'module' {}, 2) Global augmentation:...

    • How do you handle module resolution fallbacks?

      Module resolution fallbacks are configured through: 1) moduleResolution in tsconfig.json, 2) baseUrl and paths for...

    • What are decorators in TypeScript and how do you enable them?

      Decorators are special declarations that can be attached to class declarations, methods, properties, or parameters....

    • What are the different types of decorators in TypeScript?

      TypeScript supports five types of decorators: 1) Class decorators (@classDecorator), 2) Method decorators...

    • How do you create and use class decorators?

      Class decorators are declared before a class declaration and receive the constructor as an argument. Example:...

    • How do method decorators work in TypeScript?

      Method decorators are declared before method declarations and receive three arguments: target (prototype),...

    • What is reflect-metadata and how is it used with decorators?

      reflect-metadata is a library that adds a polyfill for the Metadata Reflection API. It's used with decorators to add...

    • How do property decorators differ from method decorators?

      Property decorators receive two arguments: target (prototype) and propertyKey (property name), unlike method...

    • What are decorator factories and how do you create them?

      Decorator factories are functions that return decorators and allow customization through parameters. Example:...

    • How do you implement parameter decorators?

      Parameter decorators are applied to method parameters and receive three arguments: target (prototype), methodName,...

    • What are accessor decorators and when should you use them?

      Accessor decorators are applied to getter/setter declarations and receive three arguments similar to method...

    • How do you combine multiple decorators?

      Multiple decorators can be applied to a declaration in sequence. They are evaluated in reverse order (bottom to...

    • What is the role of metadata in TypeScript decorators?

      Metadata allows storing additional information about classes, methods, and properties that can be accessed at...

    • How do you implement validation using decorators?

      Validation decorators can be implemented using property or parameter decorators with metadata. Example: function...

    • What are the common use cases for decorators?

      Common use cases include: 1) Logging and monitoring, 2) Property validation, 3) Dependency injection, 4) Method...

    • How do you use decorators for dependency injection?

      Decorators can implement dependency injection by using metadata to store and retrieve dependencies. Example:...

    • What are the limitations of decorators in TypeScript?

      Limitations include: 1) Experimental feature requiring compiler flag, 2) Can't decorate declarations in .d.ts files,...

    • How do you implement memoization using decorators?

      Memoization decorators cache function results based on arguments. Example: function memoize(target: any, key:...

    • What is design-time type metadata and how is it used?

      Design-time type metadata is automatically generated when emitDecoratorMetadata is enabled. It includes type...

    • How do you implement method overriding detection using decorators?

      Method override decorators can verify proper method overriding. Example: function override(target: any, key: string,...

    • What are the best practices for using decorators?

      Best practices include: 1) Use decorator factories for configuration, 2) Keep decorators focused and single-purpose,...

    • How do you implement lazy initialization using decorators?

      Lazy initialization decorators delay property initialization until first access. Example: function...

    • How do you handle async operations in decorators?

      Async operations in decorators require special handling since decorators run during class definition. Example:...

    • What are the differences between ES decorators and TypeScript decorators?

      Key differences include: 1) Syntax variations, 2) TypeScript decorators are experimental while ES decorators are...

    • How do you implement custom error types in TypeScript?

      Custom error types can be created by extending the Error class. Example: class ValidationError extends Error {...

    • What are union types in error handling and how do you use them?

      Union types in error handling allow functions to return either a success value or an error type. Example: type...

    • How do you handle async errors in TypeScript?

      Async errors can be handled using try-catch with async/await or .catch() with Promises. Example: async function...

    • What are type guards in error handling?

      Type guards help narrow down error types for proper handling. Example: function isNetworkError(error: unknown):...

    • How do you use the 'unknown' type for error handling?

      The 'unknown' type is safer than 'any' for error handling as it requires type checking before use. Example: function...

    • What debugging tools and techniques are available for TypeScript?

      TypeScript debugging tools include: 1) Source maps for debugging compiled code, 2) VS Code's built-in debugger, 3)...

    • How do you implement error boundaries in TypeScript?

      Error boundaries are implemented using class components with error handling lifecycle methods. Example: class...

    • What is the role of source maps in TypeScript debugging?

      Source maps enable debugging of TypeScript code directly, even though the browser runs compiled JavaScript. They map...

    • How do you handle type assertions in error handling?

      Type assertions should be used carefully in error handling to maintain type safety. Example: function...

    • What are the best practices for error handling in TypeScript?

      Best practices include: 1) Use custom error classes for specific error types, 2) Implement type-safe error handling...

    • How do you implement error logging in TypeScript?

      Error logging can be implemented using a centralized error logging service. Example: class ErrorLogger { static...

    • What is the difference between throw and reject in TypeScript?

      throw is used for synchronous error handling and immediately stops execution, while reject is used in Promises for...

    • How do you debug TypeScript tests?

      TypeScript tests can be debugged using: 1) Jest's debugger with ts-jest, 2) VS Code's debug configuration for tests,...

    • How do you implement retry logic with error handling?

      Retry logic can be implemented using recursive functions or libraries with proper error handling. Example: async...

    • What are conditional types in error handling?

      Conditional types help create type-safe error handling patterns. Example: type ErrorResponse<T> = T extends Error ?...

    • How do you handle Promise rejections in TypeScript?

      Promise rejections can be handled using .catch(), try-catch with async/await, or global handlers. Example:...

    • What are discriminated unions in error handling?

      Discriminated unions provide type-safe error handling by using a common property to discriminate between success and...

    • How do you debug memory leaks in TypeScript applications?

      Memory leaks can be debugged using: 1) Chrome DevTools Memory panel, 2) Heap snapshots, 3) Memory allocation...

    • What are error handling patterns for TypeScript decorators?

      Decorators can implement error handling through method wrapping. Example: function catchErrors() { return...

    • How do you implement circuit breakers in TypeScript?

      Circuit breakers prevent cascading failures by stopping operations after too many errors. Example: class...

    • What is tsconfig.json and what are its key components?

      tsconfig.json is the main configuration file for TypeScript projects. Key components include: 1) compilerOptions for...

    • What are the important compiler options in TypeScript?

      Key compiler options include: 1) target (specifies ECMAScript target version), 2) module (module code generation),...

    • How do you configure module resolution in TypeScript?

      Module resolution is configured through tsconfig.json options: 1) moduleResolution ('node' or 'classic'), 2) baseUrl...

    • How do you integrate TypeScript with build tools like webpack?

      TypeScript integration with webpack requires: 1) ts-loader or babel-loader with @babel/preset-typescript, 2) source...

    • What are project references in TypeScript?

      Project references allow splitting TypeScript projects into smaller pieces for better organization and build...

    • How do you configure TypeScript for different environments?

      Different environments can be configured using: 1) Multiple tsconfig files (tsconfig.dev.json, tsconfig.prod.json),...

    • What are declaration files and how do you generate them?

      Declaration files (.d.ts) provide type information for JavaScript code. They can be generated using the declaration...

    • How do you configure strict type checking in TypeScript?

      Strict type checking is configured using the strict flag and individual flags: 1) strictNullChecks, 2)...

    • What are the TypeScript tooling options for code editors?

      TypeScript tooling options include: 1) VS Code with built-in TypeScript support, 2) WebStorm with TypeScript...

    • How do you configure path aliases in TypeScript?

      Path aliases are configured using baseUrl and paths in tsconfig.json. Example: { 'compilerOptions': { 'baseUrl':...

    • What are the best practices for organizing TypeScript projects?

      Best practices include: 1) Using project references for large codebases, 2) Consistent file/folder structure, 3)...

    • How do you configure TypeScript for monorepos?

      Monorepo configuration involves: 1) Using project references, 2) Setting up shared configurations, 3) Configuring...

    • What are TypeScript Language Service plugins?

      Language Service plugins extend TypeScript's language service functionality. They can add custom type checking, code...

    • How do you configure incremental compilation in TypeScript?

      Incremental compilation is configured using: 1) incremental flag, 2) tsBuildInfoFile option, 3) composite project...

    • What are the different module systems supported by TypeScript?

      TypeScript supports multiple module systems: 1) ES Modules (import/export), 2) CommonJS (require/exports), 3) AMD,...

    • How do you configure source maps in TypeScript?

      Source maps are configured using: 1) sourceMap compiler option, 2) sourceRoot option, 3) mapRoot option. Example: {...

    • What are the different ways to handle assets and resources in TypeScript?

      Assets can be handled through: 1) Declaration files for non-code assets, 2) Module declarations for imports, 3)...

    • How do you configure TypeScript for testing environments?

      Testing configuration includes: 1) Separate tsconfig.test.json, 2) Jest configuration with ts-jest, 3) Test-specific...

    • What are the different build modes in TypeScript?

      TypeScript supports different build modes: 1) Regular compilation (tsc), 2) Watch mode (tsc -w), 3) Project...

    • How do you configure TypeScript for different module bundlers?

      Configuration varies by bundler: 1) Webpack: ts-loader or babel-loader, 2) Rollup: @rollup/plugin-typescript, 3)...

What is TypeScript and how does it differ from JavaScript?

TypeScript is a strongly typed, object-oriented programming language that builds on JavaScript. It is a superset of JavaScript that adds optional static typing, classes, interfaces, and modules. The key differences include: static typing, enhanced IDE support, object-oriented features, and compilation to JavaScript. TypeScript code needs to be compiled into JavaScript before it can be run in a browser or Node.js environment.

What are the basic data types in TypeScript?

TypeScript includes several basic data types: number (for both integers and floating-point values), string (for text), boolean (true/false), null, undefined, void (absence of value), any (dynamic typing), never (never occurs), and symbol (unique identifiers). It also supports arrays, tuples, and custom types through interfaces and type aliases.

How do you declare variables with type annotations in TypeScript?

In TypeScript, variables can be declared with type annotations using the colon (:) syntax. For example: 'let name: string = "John"', 'let age: number = 25', 'let isStudent: boolean = true'. Type annotations are optional due to TypeScript's type inference, but they make the code more explicit and self-documenting.

What is type inference in TypeScript?

Type inference is TypeScript's ability to automatically determine types of variables based on their values and usage. When you declare a variable with an initial value, TypeScript will use that value to infer its type. For example, 'let name = "John"' will be inferred as string type. This reduces the need for explicit type annotations while maintaining type safety.

Explain the 'any' type in TypeScript and when should it be used?

The 'any' type is a dynamic type that can hold values of any type. It effectively opts out of type checking for that variable. While it provides flexibility, it should be used sparingly as it defeats the purpose of TypeScript's type system. Common use cases include: working with dynamic data, gradual migration from JavaScript, and when dealing with third-party libraries without type definitions.

What is the difference between 'interface' and 'type' in TypeScript?

Both interface and type are used to define custom types, but they have some differences. Interfaces are extensible through declaration merging (can be added to later), while types are not. Interfaces can only describe object shapes, while types can also create unions, intersections, and other complex types. Generally, interfaces are preferred when defining object shapes, while types are better for aliases and complex type manipulations.

How does TypeScript handle null and undefined?

TypeScript treats null and undefined as distinct types. By default, with strict null checks enabled (strictNullChecks compiler option), you cannot assign null or undefined to a variable unless its type explicitly allows it. You can use union types to allow null or undefined values, such as 'let name: string | null = null'. This helps prevent null reference errors common in JavaScript.

What are literal types in TypeScript?

Literal types are specific value types in TypeScript where you can specify the exact value a variable can have. For example: 'let direction: "north" | "south" | "east" | "west"'. This creates a type that can only have those specific string values. Literal types can be strings, numbers, or boolean values, and are often used in union types to create enumerated sets of allowed values.

Explain type assertions in TypeScript and when to use them.

Type assertions are a way to tell the TypeScript compiler that you know better about the type of a value. They can be written in two ways: using angle brackets '<type>' or the 'as' keyword. For example: 'let someValue: any = "hello"; let strLength: number = (<string>someValue).length;' or 'let strLength: number = (someValue as string).length;'. They should be used sparingly and only when you have more information about a type than TypeScript can determine.

What is the 'never' type in TypeScript and when is it used?

The 'never' type represents values that never occur. It is used for functions that never return (throw an error or have infinite loops), and in type operations that result in no possible values. It's a bottom type, meaning it's assignable to every type, but no type is assignable to never (except never itself). Common use cases include error handling functions and exhaustive type checks.

How do you work with arrays in TypeScript?

Arrays in TypeScript can be typed in two ways: using the type followed by [] (e.g., 'number[]') or using the generic Array<type> syntax (e.g., 'Array<number>'). You can also create arrays of multiple types using union types. TypeScript provides type checking for array operations and methods. Example: 'let numbers: number[] = [1, 2, 3]' or 'let numbers: Array<number> = [1, 2, 3]'.

What are union types in TypeScript?

Union types allow a variable to hold values of multiple types. They are created using the | operator. For example: 'let id: string | number' means id can be either a string or a number. Union types are useful when a value could be one of several types, and TypeScript will ensure type safety by only allowing operations that are valid for all possible types in the union.

Explain the concept of type narrowing in TypeScript.

Type narrowing is the process of refining types to more specific ones based on type guards and conditional checks. Common type narrowing techniques include typeof checks, instanceof operators, in operator, and custom type predicates. For example, if you have a union type 'string | number' and check typeof x === 'string', TypeScript will narrow the type to string within that conditional block.

What are type guards in TypeScript?

Type guards are expressions that perform runtime checks to guarantee the type of a value in a scope. They can be built-in (typeof, instanceof), custom functions (user-defined type predicates using 'is'), or the 'in' operator. Type guards help TypeScript narrow down types in conditional blocks, making the code more type-safe. Example: 'function isString(value: any): value is string { return typeof value === "string"; }'

How do you use enums in TypeScript?

Enums allow defining a set of named numeric constants. There are numeric enums (default values auto-increment from 0) and string enums (must set all values explicitly). Example: 'enum Direction { North, South, East, West }' or 'enum Direction { North = "N", South = "S" }'. Enums can be used as types and values, and TypeScript provides type safety when working with enum values.

What are mapped types in TypeScript?

Mapped 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.

Explain conditional types in TypeScript.

Conditional 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.

What is the keyof operator in TypeScript?

The 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'

How do intersection types work in TypeScript?

Intersection 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.

What is the typeof operator in TypeScript and how does it differ from JavaScript's typeof?

TypeScript'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 }

What are utility types in TypeScript and name some common ones.

Utility 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>.

How do you use the infer keyword in TypeScript?

The 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.

What is type widening and narrowing in TypeScript?

Type 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.

How do you create type aliases in TypeScript?

Type 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.

Explain index types and index signatures in TypeScript.

Index 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.

What is the purpose of the unknown type in TypeScript?

The 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.

How do you use template literal types in TypeScript?

Template 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.

What are discriminated unions in TypeScript?

Discriminated 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.

How do you use the Omit utility type?

Omit<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 }

What is the difference between type assertions and type declarations?

Type 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)

How do you use the Pick utility type?

Pick<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 }

What are recursive types in TypeScript?

Recursive 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.

How do you use the ReturnType utility type?

ReturnType<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 }

What is the Readonly utility type and when should you use it?

Readonly<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.

How do you use lookup types in TypeScript?

Lookup 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.

What are literal type widening and const assertions?

Literal 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.

How do you use the Extract utility type?

Extract<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.

What is the difference between Record and index signatures?

Record<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 }.

What are classes in TypeScript and how do they differ from JavaScript classes?

TypeScript classes are blueprints for creating objects that extend JavaScript classes with additional features like access modifiers (public, private, protected), parameter properties, abstract classes, and interface implementation. They provide compile-time type checking and better encapsulation. Example: class Person { private name: string; constructor(name: string) { this.name = name; } }

Explain access modifiers in TypeScript classes.

TypeScript supports three access modifiers: public (default, accessible everywhere), private (only within the declaring class), and protected (within declaring class and derived classes). These modifiers help enforce encapsulation and control access to class members. Example: class Employee { private salary: number; protected id: string; public name: string; }

What are abstract classes in TypeScript?

Abstract classes are base classes that cannot be instantiated directly and may contain abstract methods that must be implemented by derived classes. They're defined using the 'abstract' keyword. They're useful for defining common behavior while forcing specific implementations in subclasses. Example: abstract class Animal { abstract makeSound(): void; move() { console.log('moving...'); } }

How does inheritance work in TypeScript?

TypeScript supports single inheritance using the 'extends' keyword. A class can inherit properties and methods from another class, and can override methods from the parent class. Multiple inheritance is achieved through interfaces. Example: class Employee extends Person { constructor(name: string, private department: string) { super(name); } }

What are parameter properties in TypeScript?

Parameter properties are a TypeScript shorthand that allows you to both declare and initialize class members in the constructor parameters. They're created by adding an access modifier to the parameter. Example: class Person { constructor(private name: string, public age: number) {} } This creates and initializes 'name' and 'age' properties automatically.

How do you implement interfaces in TypeScript classes?

Classes can implement interfaces using the 'implements' keyword. The class must provide implementations for all properties and methods defined in the interface. Multiple interfaces can be implemented using comma separation. Example: interface Printable { print(): void; } class Document implements Printable { print() { console.log('printing...'); } }

What are static members in TypeScript classes?

Static members (properties and methods) belong to the class itself rather than instances of the class. They're defined using the 'static' keyword and are accessed using the class name. Example: class Calculator { static PI = 3.14159; static add(x: number, y: number): number { return x + y; } }

How do you use getters and setters in TypeScript?

TypeScript supports JavaScript's get and set accessors with additional type safety. They allow you to add logic when accessing or modifying class properties. Example: class Circle { private _radius: number; get radius(): number { return this._radius; } set radius(value: number) { if (value >= 0) this._radius = value; } }

What is method overriding in TypeScript?

Method overriding allows a subclass to provide a specific implementation of a method that is already defined in its parent class. TypeScript ensures type safety in overridden methods. Example: class Animal { makeSound() { return 'noise'; } } class Dog extends Animal { override makeSound() { return 'woof'; } }

How do you implement polymorphism in TypeScript?

Polymorphism in TypeScript can be achieved through method overriding and interfaces. It allows objects of different classes to be treated as objects of a common base class or interface. Example: interface Shape { area(): number; } class Circle implements Shape { area() { return Math.PI * r * r; } } class Rectangle implements Shape { area() { return w * h; } }

What are private constructors and what are they used for?

Private constructors prevent class instantiation from outside the class. They're commonly used in singleton pattern implementation or utility classes that shouldn't be instantiated. Example: class Utility { private constructor() {} static helper() { return 'help'; } }

How do you implement the Singleton pattern in TypeScript?

Singleton pattern ensures a class has only one instance. In TypeScript, it's implemented using a private constructor and static instance. Example: class Singleton { private static instance: Singleton; private constructor() {} static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; } }

What is the 'readonly' modifier and how is it used in classes?

The 'readonly' modifier makes class properties immutable after initialization. They must be initialized at declaration or in the constructor. Example: class Config { readonly apiKey: string; constructor(key: string) { this.apiKey = key; } } Once set, readonly properties cannot be changed.

How do you handle method overloading in TypeScript?

TypeScript supports method overloading through function declarations with different parameter types or numbers. Implementation is done with a single function that handles all overloads. Example: class Calculator { add(x: number, y: number): number; add(x: string, y: string): string; add(x: any, y: any): any { return x + y; } }

What are abstract methods and when should you use them?

Abstract methods are methods declared in abstract classes without implementation. They must be implemented by derived classes. They're used when a base class knows a method is needed but specific implementation depends on the derived class. Example: abstract class Shape { abstract calculateArea(): number; }

How do you implement the Factory pattern in TypeScript?

The Factory pattern provides an interface for creating objects without specifying exact classes. In TypeScript, it's implemented using abstract classes or interfaces with factory methods. Example: abstract class Creator { abstract createProduct(): Product; } class ConcreteCreator extends Creator { createProduct(): Product { return new ConcreteProduct(); } }

What is the protected constructor pattern?

Protected constructors allow instantiation only from within the class itself or its derived classes. This pattern is useful for creating base classes that shouldn't be instantiated directly but can be extended. Example: class Base { protected constructor() {} } class Derived extends Base { constructor() { super(); } }

How do you implement mixins in TypeScript?

Mixins are a way to combine multiple classes into one. TypeScript implements mixins using class expressions and a helper function. Example: type Constructor<T = {}> = new (...args: any[]) => T; function Timestamped<TBase extends Constructor>(Base: TBase) { return class extends Base { timestamp = Date.now(); }; }

What are index signatures in classes?

Index signatures in classes allow you to define dynamic properties with a specific type. They're defined using [key: string]: type syntax. Example: class Dictionary { [key: string]: string; constructor() {} add(key: string, value: string) { this[key] = value; } }

How do you implement the Observer pattern in TypeScript?

The Observer pattern is implemented using interfaces for Subject and Observer, with the Subject maintaining a list of observers and notifying them of changes. Example: interface Observer { update(data: any): void; } class Subject { private observers: Observer[] = []; addObserver(observer: Observer) { this.observers.push(observer); } notify(data: any) { this.observers.forEach(observer => observer.update(data)); } }

What is the difference between composition and inheritance in TypeScript?

Composition involves creating complex objects by combining simpler ones, while inheritance creates relationships between classes. Composition is often preferred as it provides more flexibility and looser coupling. Example of composition: class Car { private engine: Engine; private wheels: Wheel[]; constructor() { this.engine = new Engine(); this.wheels = [new Wheel(), new Wheel(), new Wheel(), new Wheel()]; } }

How do you use the 'super' keyword in TypeScript?

The 'super' keyword is used to call methods or access properties on the parent class. It's commonly used in constructors of derived classes and when overriding methods. Example: class Child extends Parent { constructor(name: string) { super(name); } override getName(): string { return 'Child: ' + super.getName(); } }

What are type guards in class hierarchies?

Type guards in class hierarchies help narrow down types when working with inheritance. The instanceof operator is commonly used as a type guard. Example: class Animal {} class Dog extends Animal { bark() {} } function makeNoise(animal: Animal) { if (animal instanceof Dog) { animal.bark(); } }

What are the different ways to define function types in TypeScript?

TypeScript offers several ways to define function types: 1) Using interface: interface Func { (x: number): number; }, 2) Type alias: type Func = (x: number) => number, 3) Arrow function syntax: let func: (x: number) => number, 4) Method signature in object type: { method(x: number): number }. Each approach has specific use cases and benefits.

How do optional parameters work in TypeScript functions?

Optional parameters are marked with a '?' after the parameter name. They must come after required parameters. Example: function greet(name: string, greeting?: string) { return greeting ? `${greeting}, ${name}!` : `Hello, ${name}!`; }. Optional parameters can be omitted when calling the function.

What are rest parameters in TypeScript functions?

Rest parameters allow functions to accept an indefinite number of arguments as an array. They're denoted by '...' before the parameter name. Example: function sum(...numbers: number[]): number { return numbers.reduce((total, n) => total + n, 0); }. Rest parameters must be the last parameter in a function.

How do you implement function overloading in TypeScript?

Function overloading involves declaring multiple function signatures followed by a single implementation that handles all cases. Example: function add(a: string, b: string): string; function add(a: number, b: number): number; function add(a: any, b: any): any { return a + b; }. The implementation must be compatible with all overload signatures.

What are generic functions in TypeScript?

Generic functions allow creating reusable functions that can work with multiple types while maintaining type safety. They use type parameters denoted by <T>. Example: function identity<T>(arg: T): T { return arg; }. Generic functions provide type inference and type safety while being flexible.

How do default parameters work in TypeScript?

Default parameters provide fallback values for parameters that are not passed to the function. Example: function greet(name: string, greeting: string = 'Hello') { return `${greeting}, ${name}!`; }. Default parameters can be of any type and can reference other parameters.

What are arrow functions in TypeScript and how do they differ from regular functions?

Arrow functions provide a concise syntax for function expressions and lexically bind 'this'. Example: let add = (a: number, b: number): number => a + b;. They differ from regular functions in that they don't have their own 'this', arguments object, super, or new.target bindings.

How do you type 'this' in function parameters?

TypeScript allows typing 'this' parameter as the first parameter in function declarations. Example: function example(this: void) {} ensures the function doesn't use 'this'. For methods: function example(this: MyClass) {} ensures 'this' is of type MyClass. This helps catch incorrect 'this' usage.

What are higher-order functions in TypeScript?

Higher-order functions are functions that take other functions as parameters or return functions. Example: function map<T, U>(arr: T[], fn: (item: T) => U): U[] { return arr.map(fn); }. They're fundamental for functional programming and enable composition and abstraction.

How do you type callbacks in TypeScript?

Callbacks can be typed using function types or interfaces. Example: interface Callback { (error: Error | null, result?: string): void; } function fetchData(callback: Callback) {}. This ensures type safety when working with asynchronous operations and event handlers.

What are function type assertions?

Function type assertions allow you to tell TypeScript that a function is of a specific type. Example: const myFunc = ((x: string) => parseInt(x)) as (x: string) => number;. They should be used sparingly as they bypass TypeScript's type checking.

How do you implement currying in TypeScript?

Currying transforms a function with multiple arguments into a sequence of functions, each taking a single argument. Example: function curry<T,U,V>(f: (x: T, y: U) => V): (x: T) => (y: U) => V { return x => y => f(x, y); }. This enables partial application and function composition.

What are function type intersections?

Function type intersections combine multiple function types into one that must satisfy all types. Example: type Combined = ((x: string) => string) & ((x: number) => number);. The resulting function must handle both string and number inputs with corresponding return types.

How do you type async functions in TypeScript?

Async functions are typed with Promise<T> where T is the type of the resolved value. Example: async function getData(): Promise<string> { const response = await fetch('api'); return response.text(); }. TypeScript ensures type safety for async/await operations.

What are generator functions in TypeScript?

Generator functions return iterables using the function* syntax and yield keyword. Example: function* range(start: number, end: number): Generator<number> { for(let i = start; i <= end; i++) yield i; }. They're useful for creating iterables and handling sequences.

How do you implement method chaining in TypeScript?

Method chaining involves returning this from methods to enable consecutive calls. Example: class Calculator { private value: number = 0; add(n: number): this { this.value += n; return this; } multiply(n: number): this { this.value *= n; return this; } }

What are function type unions?

Function type unions allow a function to have multiple possible types. Example: type StringOrNumberFunc = ((x: string) => string) | ((x: number) => number);. When using such functions, TypeScript ensures type safety by requiring type checking or overloads.

How do you type function decorators?

Function decorators are typed as functions that take a function descriptor and return a new descriptor or value. Example: function logged(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const original = descriptor.value; descriptor.value = function(...args: any[]) { console.log(`Calling ${propertyKey}`); return original.apply(this, args); }; }

What is function type inference in TypeScript?

TypeScript can infer function return types and sometimes parameter types based on usage and context. Example: function map<T, U>(array: T[], func: (item: T) => U): U[] { return array.map(func); }. TypeScript infers the return type U[] based on the mapping function.

How do you implement function composition in TypeScript?

Function composition combines multiple functions into a single function, applying them in sequence. Example: const compose = <T,U,V>(f: (x: U) => V, g: (x: T) => U) => (x: T): V => f(g(x));. This enables building complex functions from simpler ones.

What are contextual typing and how does it work with functions?

Contextual typing allows TypeScript to infer types based on the context where a function is used. Example: const numbers = [1, 2, 3].map(n => n * 2); TypeScript infers that the arrow function parameter n is a number based on the array's type.

How do you type event handlers in TypeScript?

Event handlers are typically typed using the appropriate event interface. Example: function handleClick(event: React.MouseEvent<HTMLButtonElement>) { console.log(event.currentTarget); }. This ensures type safety when working with DOM events and framework-specific event systems.

What are call signatures and construct signatures?

Call signatures define how a function can be called, while construct signatures define how a function can be used with 'new'. Example: interface CallableConstructable { (x: string): string; new(x: string): object; }. This allows typing functions that can be both called and constructed.

How do you type function properties?

Function properties are typed using regular property syntax on function types. Example: interface FunctionWithProps { (x: number): number; defaultValue: number; }. This allows creating functions with additional properties or methods.

What are function type constraints in generics?

Function type constraints limit what types can be used with generic functions. Example: function longest<T extends { length: number }>(a: T, b: T): T { return a.length >= b.length ? a : b; }. This ensures the generic type T has a length property.

What are generics in TypeScript and why are they useful?

Generics are a way to create reusable components that can work with multiple types while maintaining type safety. They allow you to write functions, classes, and interfaces that can work with any data type while preserving type information. Example: function identity<T>(arg: T): T { return arg; }. Generics provide type safety, code reusability, and prevent code duplication.

How do you use generic constraints in TypeScript?

Generic constraints limit what types can be used with a generic type using the 'extends' keyword. Example: function getLength<T extends { length: number }>(arg: T): number { return arg.length; }. This ensures that the generic type T must have a length property. Constraints help enforce type safety while maintaining flexibility.

What are generic interfaces and how do you implement them?

Generic interfaces are interfaces that can work with multiple types. Example: interface Container<T> { value: T; getValue(): T; }. Implementation: class NumberContainer implements Container<number> { constructor(public value: number) {} getValue(): number { return this.value; } }. They enable type-safe, reusable interface definitions.

What are conditional types in TypeScript?

Conditional types select a type based on a condition, using syntax similar to ternary operators: T extends U ? X : Y. Example: type NonNullable<T> = T extends null | undefined ? never : T. They're powerful for creating complex type transformations and can be used with mapped types and unions.

How do you use generic type inference?

TypeScript can infer generic types from usage context. Example: function identity<T>(arg: T): T { return arg; } let output = identity('hello'); // T is inferred as string. Type inference reduces verbosity while maintaining type safety. The compiler uses argument types to determine generic type parameters.

What are type parameters in generics?

Type parameters are placeholders for types in generic definitions, conventionally denoted by T, U, K, V, etc. Example: function swap<T, U>(tuple: [T, U]): [U, T] { return [tuple[1], tuple[0]]; }. They can have constraints, defaults, and be used in multiple places within the generic definition.

How do you use generic classes in TypeScript?

Generic classes use type parameters to create flexible, reusable class definitions. Example: class Stack<T> { private items: T[] = []; push(item: T) { this.items.push(item); } pop(): T | undefined { return this.items.pop(); } }. They maintain type safety while working with different data types.

What are mapped types and how do they work?

Mapped types create new types by transforming properties of existing types. Example: type Readonly<T> = { readonly [P in keyof T]: T[P] }. They can add/remove modifiers (readonly, optional) and transform property types. Mapped types are powerful for type transformations and creating utility types.

How do you use the infer keyword in conditional types?

The infer keyword extracts type information within conditional types. Example: type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any. This extracts the return type R from a function type. infer is powerful for type inference and extraction in complex scenarios.

What are generic type defaults?

Generic type defaults provide fallback types when no type argument is specified. Example: interface Container<T = string> { value: T; }. When no type is provided, string is used: let container: Container = { value: 'hello' }. They help make generic types more convenient to use.

How do you use multiple type parameters in generics?

Multiple type parameters allow generics to work with multiple types simultaneously. Example: function pair<T, U>(first: T, second: U): [T, U] { return [first, second]; }. The order and naming of type parameters matter for readability and understanding the relationship between types.

What are index types and how do they work with generics?

Index types allow type-safe access to properties using dynamic keys. Example: function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }. This ensures type safety when accessing object properties dynamically.

How do you create generic type guards?

Generic type guards combine generics with type predicates. Example: function isOfType<T>(value: any, property: keyof T): value is T { return property in value; }. They provide type-safe runtime checks while maintaining generic type information.

What are union and intersection types in generics?

Union and intersection types can be used with generics to create flexible type combinations. Example: function process<T, U>(value: T | U): T & U { ... }. This allows working with types that can be either T or U while producing a type that has properties of both.

How do you use generic type aliases?

Generic type aliases create reusable type definitions with type parameters. Example: type Result<T> = { success: boolean; data?: T; error?: string; }. They provide flexibility while maintaining type safety and can be used with unions, intersections, and mapped types.

How do you use generic constraints with unions and intersections?

Generic constraints can use union and intersection types to create complex type requirements. Example: function merge<T extends object, U extends object>(obj1: T, obj2: U): T & U { return { ...obj1, ...obj2 }; }. This ensures type parameters meet specific criteria while allowing flexible combinations.

What are branded types and how do they work with generics?

Branded types are nominal types created using intersection with unique symbols. Example: type Brand<T, B> = T & { __brand: B }; type USD = Brand<number, 'USD'>. They provide type safety by preventing mixing of similarly structured but semantically different types.

How do you use keyof with generics?

The keyof operator can be used with generics to create type-safe property access. Example: function getNestedValue<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }. This ensures type safety when accessing object properties dynamically.

What are variadic tuple types?

Variadic tuple types allow working with tuples of variable length in a type-safe way. Example: type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U]. They're useful for type-safe array operations and function parameter handling.

How do you use template literal types with generics?

Template literal types can be combined with generics to create dynamic string types. Example: type PropEventType<T extends string> = `${T}Changed`; This creates new string literal types based on generic parameters.

What are generic type assertions?

Generic type assertions allow specifying type parameters when using type assertions. Example: function create<T>(factory: { new(): T }): T { return new factory() as T; }. They provide type safety when working with dynamic type creation.

How do you use generic default types with constraints?

Generic default types can be combined with constraints to provide flexible yet safe defaults. Example: interface Container<T extends object = { id: string }> { data: T; }. This ensures the default type meets the constraint while allowing other compatible types.

What are distributive conditional types?

Distributive conditional types apply conditions to each member of a union type. Example: type ToArray<T> = T extends any ? T[] : never; type NumberOrStringArray = ToArray<number | string>; // number[] | string[]. They're useful for transforming union types.

How do you create type-safe event emitters with generics?

Generic event emitters provide type safety for event handling. Example: class EventEmitter<Events extends Record<string, any>> { emit<E extends keyof Events>(event: E, data: Events[E]): void { ... } }. This ensures event names and data types match at compile time.

What is the difference between interfaces and type aliases in TypeScript?

Key differences include: 1) Interfaces are extendable through declaration merging while type aliases are not, 2) Interfaces can only describe object shapes while type aliases can create unions, primitives, and tuples, 3) Interfaces are better for defining contracts in object-oriented programming while type aliases are preferable for functional programming patterns. Example: interface vs type Point = { x: number; y: number; }

How does interface inheritance work in TypeScript?

Interfaces can inherit from other interfaces using the 'extends' keyword. They can extend multiple interfaces, creating a combination of all properties. Example: interface Shape { color: string; } interface Circle extends Shape { radius: number; } A class implementing Circle must provide both color and radius properties.

What are optional properties in interfaces?

Optional properties in interfaces are marked with a '?' symbol after the property name. They don't need to be implemented when using the interface. Example: interface User { name: string; email?: string; } This means email is optional and can be undefined.

How do you implement readonly properties in interfaces?

Readonly properties are marked with the 'readonly' modifier and cannot be changed after initialization. Example: interface Point { readonly x: number; readonly y: number; } This ensures immutability of these properties after they are set initially.

What are index signatures in interfaces?

Index signatures allow interfaces to describe objects with dynamic property names. Example: interface StringMap { [key: string]: string; } This means the object can have any number of string properties, where both the key and value are strings.

How do you define function types in interfaces?

Function types in interfaces can be defined using call signatures. Example: interface Calculation { (x: number, y: number): number; } This defines an interface for a function that takes two numbers and returns a number. You can also use method syntax: interface Math { add(x: number, y: number): number; }

What is declaration merging with interfaces?

Declaration merging allows multiple interface declarations with the same name to be automatically combined. Example: interface User { name: string; } interface User { age: number; } Results in an interface requiring both name and age. This is unique to interfaces and not available with type aliases.

How do you use generics with interfaces?

Interfaces can use generic type parameters to create flexible, reusable definitions. Example: interface Container<T> { value: T; getValue(): T; } This allows the interface to work with any type while maintaining type safety.

What are hybrid types in interfaces?

Hybrid types combine function types with object properties. Example: interface Counter { (start: number): string; interval: number; reset(): void; } This creates an interface that can be both called as a function and has properties/methods.

How do you extend multiple interfaces?

An interface can extend multiple interfaces using comma-separated names. Example: interface Shape { color: string; } interface Sizeable { size: number; } interface Circle extends Shape, Sizeable { radius: number; } This combines all properties from the extended interfaces.

What are recursive types in interfaces?

Recursive types are interfaces that reference themselves in their definition. Example: interface TreeNode { value: string; children?: TreeNode[]; } This creates a tree-like structure where each node can have child nodes of the same type.

How do you use mapped types with interfaces?

Mapped types can be used to transform interface properties systematically. Example: type Readonly<T> = { readonly [P in keyof T]: T[P] }; interface User { name: string; age: number; } type ReadonlyUser = Readonly<User>;

What are utility types for interfaces?

Utility types provide common type transformations for interfaces. Example: interface User { name: string; age?: number; } type RequiredUser = Required<User>; type PartialUser = Partial<User>; These transform optional properties to required and vice versa.

How do you implement method overloading in interfaces?

Method overloading in interfaces is achieved by declaring multiple function signatures. Example: interface Document { createElement(tagName: any): any; createElement(tagName: 'div'): HTMLDivElement; createElement(tagName: 'span'): HTMLSpanElement; }

What are union and intersection types with interfaces?

Union types (|) allow a value to be one of several types, while intersection types (&) combine multiple types. Example: interface Bird { fly(): void; } interface Fish { swim(): void; } type Pet = Bird | Fish; type Amphibian = Bird & Fish;

How do you use type guards with interfaces?

Type guards help narrow down interface types in conditional blocks. Example: interface Bird { fly(): void; } interface Fish { swim(): void; } function isBird(pet: Bird | Fish): pet is Bird { return (pet as Bird).fly !== undefined; }

What are computed properties in interfaces?

Computed properties allow property names to be expressions. Example: type Events = 'click' | 'focus'; interface Handlers { [K in Events]: (event: any) => void; } This creates properties for each event type automatically.

How do you use interfaces with classes?

Classes can implement interfaces using the 'implements' keyword. Example: interface Printable { print(): void; } class Document implements Printable { print() { console.log('printing...'); } } The class must provide implementations for all interface members.

What are literal types in interfaces?

Literal types specify exact values that a property must have. Example: interface Config { mode: 'development' | 'production'; port: 80 | 443; } This ensures properties can only have specific values.

How do you use interfaces with generics constraints?

Interfaces can be used as constraints for generic types. Example: interface Lengthwise { length: number; } function logLength<T extends Lengthwise>(arg: T): number { return arg.length; } This ensures the generic type has a length property.

What are optional methods in interfaces?

Optional methods in interfaces are marked with '?' and don't need to be implemented. Example: interface Logger { log(message: string): void; error?(error: Error): void; } This makes the error method optional.

How do you use interfaces with array types?

Interfaces can describe array-like structures using index signatures or extending Array. Example: interface StringArray { [index: number]: string; length: number; } interface MyArray<T> extends Array<T> { getFirst(): T; }

What are constructor signatures in interfaces?

Constructor signatures define how a class constructor should look. Example: interface ClockConstructor { new (hour: number, minute: number): ClockInterface; } This ensures classes implementing the interface have the specified constructor.

How do you use interfaces with function overloading?

Interfaces can define multiple call signatures for function overloading. Example: interface StringNumberFunction { (str: string): number; (str: string, radix: number): number; } This allows functions to be called with different parameter combinations.

What are static properties in interfaces?

Interfaces can define static members that must be implemented by the class itself rather than instances. Example: interface ClockConstructor { new (): ClockInterface; currentTime: Date; } The currentTime property must be implemented as a static property.

What are ES modules in TypeScript and how do they differ from namespaces?

ES modules are the standard JavaScript module system that TypeScript supports. They use import/export syntax and provide better code organization and dependency management. Unlike namespaces (internal modules), ES modules are file-based, support better tree-shaking, and are the preferred way to organize code. Example: export class MyClass {} and import { MyClass } from './myModule';

How do you use export and import statements in TypeScript?

TypeScript supports various export/import syntaxes: 1) Named exports: export { MyClass }; 2) Default exports: export default MyClass; 3) Import named: import { MyClass } from './module'; 4) Import default: import MyClass from './module'; 5) Import all: import * as module from './module'. Each type serves different purposes in module organization.

What are namespaces in TypeScript and when should you use them?

Namespaces (formerly 'internal modules') are TypeScript's own module system for encapsulating code. They use the namespace keyword and are useful for avoiding name collisions in global scope. Example: namespace Mathematics { export function add(x: number, y: number): number { return x + y; } }. However, ES modules are generally preferred for modern applications.

How do you use barrel exports in TypeScript?

Barrel exports consolidate multiple exports into a single entry point using an index.ts file. Example: export * from './math'; export * from './string'; export * from './array';. This simplifies imports by providing a single import point and helps manage large codebases by organizing related functionality.

What is module augmentation in TypeScript?

Module augmentation allows you to add new declarations to existing modules. Example: declare module 'lodash' { interface LoDashStatic { myCustomFunction(arg: string): number; } }. This is useful for adding type definitions to existing JavaScript modules or extending third-party module declarations.

How do you handle circular dependencies in TypeScript modules?

Circular dependencies occur when two modules import each other. They can be resolved by: 1) Restructuring code to avoid circularity, 2) Using interfaces instead of concrete implementations, 3) Moving shared code to a separate module, 4) Using import type for type-only imports. Example: import type { User } from './user' instead of import { User } from './user'.

What are ambient modules in TypeScript?

Ambient modules declare types for JavaScript modules that don't have TypeScript declarations. They use declare module syntax. Example: declare module 'my-library' { export function doSomething(): void; }. They're commonly used in .d.ts files to provide type information for JavaScript libraries.

How do you use namespace merging in TypeScript?

Namespace merging allows combining multiple namespace declarations with the same name. Example: namespace Animals { export class Dog {} } namespace Animals { export class Cat {} }. This creates a single namespace containing both Dog and Cat classes. It's similar to interface merging but for namespaces.

What are the different module resolution strategies in TypeScript?

TypeScript supports several module resolution strategies: 1) Classic: Legacy resolution for AMD/System.js, 2) Node: Follows Node.js module resolution, 3) baseUrl: Resolves modules relative to a base directory, 4) paths: Allows custom module path mapping. These are configured in tsconfig.json using the moduleResolution option.

How do you use dynamic imports in TypeScript?

Dynamic imports allow loading modules on demand using import() syntax. Example: async function loadModule() { const module = await import('./myModule'); module.doSomething(); }. This enables code-splitting and lazy loading of modules for better performance.

What are declaration files (.d.ts) and how do they work with modules?

Declaration files (.d.ts) contain type information for JavaScript modules. They define the shape of modules without implementation details. Example: declare module 'my-module' { export interface Config { debug: boolean; } export function initialize(config: Config): void; }. They enable TypeScript to understand external JavaScript libraries.

How do you use re-exports in TypeScript modules?

Re-exports allow you to export items from other modules. Syntax includes: export { Something } from './other', export * from './other', and export { Something as OtherThing } from './other'. This helps create clean public APIs and organize code hierarchy.

What are the best practices for organizing modules in TypeScript?

Best practices include: 1) One class/feature per file, 2) Use barrel exports (index.ts) for related features, 3) Keep modules small and focused, 4) Use meaningful file names matching exported content, 5) Group related functionality in directories, 6) Use clear import paths, 7) Avoid circular dependencies. This improves code maintainability and readability.

How do you handle module path aliases in TypeScript?

Module path aliases are configured in tsconfig.json using the paths option. Example: { 'compilerOptions': { 'baseUrl': '.', 'paths': { '@app/*': ['src/app/*'] } } }. This allows using @app/feature instead of relative paths, making imports cleaner and more maintainable.

What is the difference between internal and external modules?

Internal modules (namespaces) use the namespace keyword and are TypeScript-specific. External modules (ES modules) use import/export syntax and are the standard JavaScript module system. Example: namespace MyNamespace {} vs. export class MyClass {}. ES modules are preferred for modern applications.

How do you use namespace exports and imports?

Namespaces use export keyword for public members and can be accessed using dot notation. Example: namespace Math { export function add(x: number, y: number): number { return x + y; } } Usage: Math.add(1, 2). For cross-file namespaces, use /// <reference path='./math.ts' /> syntax.

What are synthetic default imports in TypeScript?

Synthetic default imports allow importing modules that don't have explicit default exports as if they did. Controlled by esModuleInterop compiler option. Example: import React from 'react' works even if React uses module.exports = React. This improves compatibility with CommonJS modules.

How do you handle module side effects in TypeScript?

Module side effects are handled using import statements without bindings. Example: import './polyfills'; This executes the module code without importing any values. It's useful for polyfills, global styles, or other code that needs to run during module initialization.

What are global modules in TypeScript?

Global modules are ambient modules that add types to the global scope. Example: declare global { interface Window { myCustomProperty: string; } }. They're useful for extending global objects or declaring global variables, but should be used sparingly to avoid polluting global namespace.

How do you use type-only imports and exports?

Type-only imports/exports are used for importing/exporting types without value emissions. Syntax: import type { MyType } from './types'; export type { MyType }. This helps reduce bundle size by removing type information during compilation while maintaining type safety.

What are the patterns for lazy loading modules in TypeScript?

Lazy loading patterns include: 1) Dynamic imports: import('./module'), 2) Route-based splitting: loadChildren in Angular routes, 3) Component-based splitting in React.lazy(). Example: const MyComponent = React.lazy(() => import('./MyComponent')). This improves initial load time by loading modules on demand.

How do you handle module resolution in monorepos?

Monorepo module resolution involves: 1) Using project references in tsconfig.json, 2) Configuring path aliases for packages, 3) Setting up proper build order, 4) Managing shared dependencies. Example: { 'references': [{ 'path': '../common' }], 'paths': { '@org/*': ['packages/*/src'] } }.

What are the different ways to handle module augmentation?

Module augmentation can be done through: 1) Declaration merging: declare module 'module' {}, 2) Global augmentation: declare global {}, 3) Namespace augmentation: namespace NS {}. Example: declare module 'express-session' { interface SessionData { userId: string; } }

How do you handle module resolution fallbacks?

Module resolution fallbacks are configured through: 1) moduleResolution in tsconfig.json, 2) baseUrl and paths for custom mappings, 3) TypeScript path mapping patterns like * and **. Example: { 'paths': { '*': ['node_modules/*', 'fallback/*'] } }. This helps handle different module formats and locations.

What are decorators in TypeScript and how do you enable them?

Decorators are special declarations that can be attached to class declarations, methods, properties, or parameters. They are enabled by setting 'experimentalDecorators: true' in tsconfig.json. Example: @decorator class Example {}. Decorators provide a way to add annotations and metadata to existing code.

What are the different types of decorators in TypeScript?

TypeScript supports five types of decorators: 1) Class decorators (@classDecorator), 2) Method decorators (@methodDecorator), 3) Property decorators (@propertyDecorator), 4) Accessor decorators (@accessorDecorator), and 5) Parameter decorators (@parameterDecorator). Each type receives different arguments and can be used for different purposes.

How do you create and use class decorators?

Class decorators are declared before a class declaration and receive the constructor as an argument. Example: function logger(target: Function) { console.log(`Creating class: ${target.name}`); } @logger class Example {}. They can modify or replace the class definition and are useful for adding metadata or behavior to classes.

How do method decorators work in TypeScript?

Method decorators are declared before method declarations and receive three arguments: target (prototype), propertyKey (method name), and descriptor (property descriptor). Example: function log(target: any, key: string, descriptor: PropertyDescriptor) { // Original method const original = descriptor.value; descriptor.value = function(...args: any[]) { console.log(`Calling ${key}`); return original.apply(this, args); }; }

What is reflect-metadata and how is it used with decorators?

reflect-metadata is a library that adds a polyfill for the Metadata Reflection API. It's used with decorators to add and read metadata about classes, methods, and properties. Enable with 'emitDecoratorMetadata: true' in tsconfig.json. Example: import 'reflect-metadata'; @Reflect.metadata('role', 'admin') class User {}

How do property decorators differ from method decorators?

Property decorators receive two arguments: target (prototype) and propertyKey (property name), unlike method decorators which also receive a descriptor. Example: function validate(target: any, key: string) { let value = target[key]; Object.defineProperty(target, key, { get: () => value, set: (newValue) => { if (!newValue) throw new Error('Value cannot be null'); value = newValue; } }); }

What are decorator factories and how do you create them?

Decorator factories are functions that return decorators and allow customization through parameters. Example: function log(prefix: string) { return function(target: any) { console.log(`${prefix}: ${target.name}`); }; } @log('MyApp') class Example {}. They provide a way to customize decorator behavior.

How do you implement parameter decorators?

Parameter decorators are applied to method parameters and receive three arguments: target (prototype), methodName, and parameterIndex. Example: function required(target: Object, propertyKey: string, parameterIndex: number) { const requiredParams = Reflect.getMetadata('required', target, propertyKey) || []; requiredParams.push(parameterIndex); Reflect.defineMetadata('required', requiredParams, target, propertyKey); }

What are accessor decorators and when should you use them?

Accessor decorators are applied to getter/setter declarations and receive three arguments similar to method decorators. Example: function enumerable(value: boolean) { return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { descriptor.enumerable = value; }; } They're useful for modifying accessor behavior.

How do you combine multiple decorators?

Multiple decorators can be applied to a declaration in sequence. They are evaluated in reverse order (bottom to top). Example: @f @g class C {}. Evaluation order: g then f. For decorator factories: @f() @g() class C {}, the factories are evaluated in order (f then g) but the decorators in reverse order.

What is the role of metadata in TypeScript decorators?

Metadata allows storing additional information about classes, methods, and properties that can be accessed at runtime. It's enabled with reflect-metadata. Example: Reflect.defineMetadata('validation', { required: true }, target, propertyKey); const metadata = Reflect.getMetadata('validation', target, propertyKey);

How do you implement validation using decorators?

Validation decorators can be implemented using property or parameter decorators with metadata. Example: function required(target: any, propertyKey: string) { const validationMetadata = { required: true }; Reflect.defineMetadata('validation', validationMetadata, target, propertyKey); } class User { @required name: string; }

What are the common use cases for decorators?

Common use cases include: 1) Logging and monitoring, 2) Property validation, 3) Dependency injection, 4) Method memoization, 5) Access control and authorization, 6) Class and property transformation, 7) API endpoint definition (e.g., in NestJS), 8) Observable properties (e.g., in Angular), 9) Type serialization/deserialization.

How do you use decorators for dependency injection?

Decorators can implement dependency injection by using metadata to store and retrieve dependencies. Example: function Injectable() { return function(target: any) { Reflect.defineMetadata('injectable', true, target); }; } @Injectable() class Service {} This pattern is used in frameworks like Angular and NestJS.

What are the limitations of decorators in TypeScript?

Limitations include: 1) Experimental feature requiring compiler flag, 2) Can't decorate declarations in .d.ts files, 3) Limited to specific declaration types (class, method, property, parameter), 4) Can't access decorated values during declaration phase, 5) No direct way to decorate local variables or function declarations.

How do you implement memoization using decorators?

Memoization decorators cache function results based on arguments. Example: function memoize(target: any, key: string, descriptor: PropertyDescriptor) { const original = descriptor.value; const cache = new Map(); descriptor.value = function(...args: any[]) { const key = JSON.stringify(args); if (cache.has(key)) return cache.get(key); const result = original.apply(this, args); cache.set(key, result); return result; }; }

What is design-time type metadata and how is it used?

Design-time type metadata is automatically generated when emitDecoratorMetadata is enabled. It includes type information for parameters, return types, and properties. Example: const paramTypes = Reflect.getMetadata('design:paramtypes', target, key); This is used by frameworks for dependency injection and validation.

How do you implement method overriding detection using decorators?

Method override decorators can verify proper method overriding. Example: function override(target: any, key: string, descriptor: PropertyDescriptor) { const baseClass = Object.getPrototypeOf(target); if (!baseClass[key]) throw new Error(`${key} doesn't override any base method`); return descriptor; } class Child extends Parent { @override method() {} }

What are the best practices for using decorators?

Best practices include: 1) Use decorator factories for configuration, 2) Keep decorators focused and single-purpose, 3) Handle errors gracefully, 4) Use meaningful names that describe behavior, 5) Document decorator requirements and effects, 6) Avoid side effects in decorator evaluation, 7) Use metadata for storing configuration, 8) Consider performance implications.

How do you implement lazy initialization using decorators?

Lazy initialization decorators delay property initialization until first access. Example: function lazy<T>(initializer: () => T) { return function(target: any, key: string) { let value: T; Object.defineProperty(target, key, { get: () => { if (!value) value = initializer(); return value; } }); }; } class Example { @lazy(() => expensiveOperation()) value: string; }

How do you handle async operations in decorators?

Async operations in decorators require special handling since decorators run during class definition. Example: function asyncInit() { return function(target: any) { return class extends target { async init() { await super.init(); // Additional async initialization } }; }; } @asyncInit() class Service { async init() { /* ... */ } }

What are the differences between ES decorators and TypeScript decorators?

Key differences include: 1) Syntax variations, 2) TypeScript decorators are experimental while ES decorators are part of the standard, 3) Different metadata handling, 4) ES decorators have additional capabilities like decorating object literals, 5) TypeScript decorators may need updates to align with ES decorator standard when finalized.

How do you implement custom error types in TypeScript?

Custom error types can be created by extending the Error class. Example: class ValidationError extends Error { constructor(message: string) { super(message); this.name = 'ValidationError'; Object.setPrototypeOf(this, ValidationError.prototype); } } This allows for type-safe error handling and custom error properties.

What are union types in error handling and how do you use them?

Union types in error handling allow functions to return either a success value or an error type. Example: type Result<T> = { success: true; data: T; } | { success: false; error: Error; }. This pattern enables type-safe error handling without throwing exceptions: function process(): Result<string> { try { return { success: true, data: 'processed' }; } catch (e) { return { success: false, error: e instanceof Error ? e : new Error(String(e)) }; } }

How do you handle async errors in TypeScript?

Async errors can be handled using try-catch with async/await or .catch() with Promises. Example: async function handleAsync() { try { await riskyOperation(); } catch (error) { if (error instanceof NetworkError) { // Handle network errors } else if (error instanceof ValidationError) { // Handle validation errors } throw error; // Re-throw unhandled errors } }

What are type guards in error handling?

Type guards help narrow down error types for proper handling. Example: function isNetworkError(error: unknown): error is NetworkError { return error instanceof NetworkError; } try { // risky operation } catch (error) { if (isNetworkError(error)) { console.log(error.statusCode); // TypeScript knows error is NetworkError } }

How do you use the 'unknown' type for error handling?

The 'unknown' type is safer than 'any' for error handling as it requires type checking before use. Example: function handleError(error: unknown) { if (error instanceof Error) { console.log(error.message); } else if (typeof error === 'string') { console.log(error); } else { console.log('Unknown error occurred'); } }

What debugging tools and techniques are available for TypeScript?

TypeScript debugging tools include: 1) Source maps for debugging compiled code, 2) VS Code's built-in debugger, 3) Chrome DevTools with source maps, 4) debugger statement, 5) console methods (log, warn, error, trace), 6) TypeScript compiler flags like --noEmitOnError, 7) Jest debugger for testing. Configuration in launch.json: { 'type': 'node', 'request': 'launch', 'sourceMaps': true }

How do you implement error boundaries in TypeScript?

Error boundaries are implemented using class components with error handling lifecycle methods. Example: class ErrorBoundary extends React.Component<Props, State> { static getDerivedStateFromError(error: Error): State { return { hasError: true, error }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { logErrorToService(error, errorInfo); } } This catches and handles errors in child components.

What is the role of source maps in TypeScript debugging?

Source maps enable debugging of TypeScript code directly, even though the browser runs compiled JavaScript. They map positions in the compiled code to the original TypeScript. Enable with 'sourceMap: true' in tsconfig.json. This allows setting breakpoints in TypeScript files and seeing TypeScript variables during debugging.

How do you handle type assertions in error handling?

Type assertions should be used carefully in error handling to maintain type safety. Example: function handleError(error: unknown) { if (error instanceof Error) { const customError = error as CustomError; // Only assert after instanceof check if (customError.code) { // Handle custom error } } }

What are the best practices for error handling in TypeScript?

Best practices include: 1) Use custom error classes for specific error types, 2) Implement type-safe error handling with union types, 3) Always check error types before using their properties, 4) Use async/await with try-catch for async operations, 5) Implement proper error logging and monitoring, 6) Use error boundaries in React applications, 7) Avoid using 'any' for error types, prefer 'unknown'.

How do you implement error logging in TypeScript?

Error logging can be implemented using a centralized error logging service. Example: class ErrorLogger { static log(error: Error, context?: object) { const errorLog = { timestamp: new Date(), name: error.name, message: error.message, stack: error.stack, context }; // Send to logging service or store locally console.error(errorLog); } }

What is the difference between throw and reject in TypeScript?

throw is used for synchronous error handling and immediately stops execution, while reject is used in Promises for asynchronous error handling. Example: function sync() { throw new Error('Sync error'); } async function async() { return Promise.reject(new Error('Async error')); } throw creates an exception, reject creates a rejected Promise.

How do you debug TypeScript tests?

TypeScript tests can be debugged using: 1) Jest's debugger with ts-jest, 2) VS Code's debug configuration for tests, 3) Chrome DevTools with karma. Example launch.json: { 'type': 'node', 'request': 'launch', 'name': 'Debug Tests', 'program': '${workspaceFolder}/node_modules/jest/bin/jest', 'args': ['--runInBand'] }

How do you implement retry logic with error handling?

Retry logic can be implemented using recursive functions or libraries with proper error handling. Example: async function retryOperation<T>(operation: () => Promise<T>, maxRetries: number): Promise<T> { try { return await operation(); } catch (error) { if (maxRetries > 0) { await delay(1000); return retryOperation(operation, maxRetries - 1); } throw error; } }

What are conditional types in error handling?

Conditional types help create type-safe error handling patterns. Example: type ErrorResponse<T> = T extends Error ? { error: T; data: null; } : { error: null; data: T; }; function handleResult<T>(result: T): ErrorResponse<T> { return result instanceof Error ? { error: result, data: null } : { error: null, data: result }; }

How do you handle Promise rejections in TypeScript?

Promise rejections can be handled using .catch(), try-catch with async/await, or global handlers. Example: window.onunhandledrejection = (event: PromiseRejectionEvent) => { console.error('Unhandled promise rejection:', event.reason); event.preventDefault(); }; This ensures all rejected Promises are handled.

What are discriminated unions in error handling?

Discriminated unions provide type-safe error handling by using a common property to discriminate between success and error states. Example: type Result<T> = { kind: 'success'; value: T; } | { kind: 'error'; error: Error; }; This enables exhaustive checking of all possible states.

How do you debug memory leaks in TypeScript applications?

Memory leaks can be debugged using: 1) Chrome DevTools Memory panel, 2) Heap snapshots, 3) Memory allocation timeline, 4) Node.js --inspect flag. Example: Taking heap snapshots: const heapSnapshot = require('heapdump'); heapSnapshot.writeSnapshot(`${Date.now()}.heapsnapshot`); Then analyze using Chrome DevTools.

What are error handling patterns for TypeScript decorators?

Decorators can implement error handling through method wrapping. Example: function catchErrors() { return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const original = descriptor.value; descriptor.value = async function(...args: any[]) { try { return await original.apply(this, args); } catch (error) { ErrorLogger.log(error); throw error; } }; }; }

How do you implement circuit breakers in TypeScript?

Circuit breakers prevent cascading failures by stopping operations after too many errors. Example: class CircuitBreaker { private failures = 0; private readonly threshold = 5; async execute<T>(operation: () => Promise<T>): Promise<T> { if (this.failures >= this.threshold) { throw new Error('Circuit breaker open'); } try { const result = await operation(); this.failures = 0; return result; } catch (error) { this.failures++; throw error; } } }

What is tsconfig.json and what are its key components?

tsconfig.json is the main configuration file for TypeScript projects. Key components include: 1) compilerOptions for configuring the TypeScript compiler, 2) include/exclude for specifying which files to compile, 3) extends for inheriting configurations, 4) files for explicitly listing files to include. Example: { 'compilerOptions': { 'target': 'ES6', 'module': 'commonjs', 'strict': true }, 'include': ['src/**/*'], 'exclude': ['node_modules'] }

What are the important compiler options in TypeScript?

Key compiler options include: 1) target (specifies ECMAScript target version), 2) module (module code generation), 3) strict (enables all strict type checking options), 4) outDir (output directory), 5) rootDir (root directory of source files), 6) sourceMap (generates source maps), 7) declaration (generates .d.ts files), 8) noImplicitAny (error on implied any types), 9) esModuleInterop (enables interop between CommonJS and ES Modules)

How do you configure module resolution in TypeScript?

Module resolution is configured through tsconfig.json options: 1) moduleResolution ('node' or 'classic'), 2) baseUrl (base directory for non-relative imports), 3) paths (path mapping for module aliases), 4) rootDirs (list of root folders). Example: { 'compilerOptions': { 'moduleResolution': 'node', 'baseUrl': './src', 'paths': { '@/*': ['*'] } } }

How do you integrate TypeScript with build tools like webpack?

TypeScript integration with webpack requires: 1) ts-loader or babel-loader with @babel/preset-typescript, 2) source map configuration, 3) resolve extensions configuration. Example webpack config: { module: { rules: [{ test: /\.tsx?$/, use: 'ts-loader' }] }, resolve: { extensions: ['.tsx', '.ts', '.js'] } }

What are project references in TypeScript?

Project references allow splitting TypeScript projects into smaller pieces for better organization and build performance. They're configured using the references field in tsconfig.json. Example: { 'references': [{ 'path': '../common' }], 'compilerOptions': { 'composite': true } }. This enables incremental compilation and better project organization.

How do you configure TypeScript for different environments?

Different environments can be configured using: 1) Multiple tsconfig files (tsconfig.dev.json, tsconfig.prod.json), 2) Environment-specific compiler options, 3) Conditional types based on environment. Example: { 'extends': './tsconfig.base.json', 'compilerOptions': { 'sourceMap': true, 'declaration': false } }

What are declaration files and how do you generate them?

Declaration files (.d.ts) provide type information for JavaScript code. They can be generated using the declaration compiler option. Example tsconfig.json: { 'compilerOptions': { 'declaration': true, 'declarationDir': './types' } }. They're useful for creating type definitions for JavaScript libraries or separating type declarations from implementation.

How do you configure strict type checking in TypeScript?

Strict type checking is configured using the strict flag and individual flags: 1) strictNullChecks, 2) strictFunctionTypes, 3) strictBindCallApply, 4) strictPropertyInitialization, 5) noImplicitAny, 6) noImplicitThis. Example: { 'compilerOptions': { 'strict': true, 'strictNullChecks': true } }

What are the TypeScript tooling options for code editors?

TypeScript tooling options include: 1) VS Code with built-in TypeScript support, 2) WebStorm with TypeScript integration, 3) ESLint with @typescript-eslint, 4) Prettier for code formatting, 5) TypeScript Language Service plugins. These provide features like IntelliSense, refactoring, and error checking.

How do you configure path aliases in TypeScript?

Path aliases are configured using baseUrl and paths in tsconfig.json. Example: { 'compilerOptions': { 'baseUrl': '.', 'paths': { '@components/*': ['src/components/*'], '@utils/*': ['src/utils/*'] } } }. This enables using imports like import { Button } from '@components/Button';

What are the best practices for organizing TypeScript projects?

Best practices include: 1) Using project references for large codebases, 2) Consistent file/folder structure, 3) Proper module organization, 4) Shared tsconfig.json settings, 5) Clear naming conventions, 6) Separation of concerns, 7) Using barrel exports (index.ts files), 8) Proper type declaration organization.

How do you configure TypeScript for monorepos?

Monorepo configuration involves: 1) Using project references, 2) Setting up shared configurations, 3) Configuring workspace dependencies, 4) Using tools like Lerna or Nx. Example: Root tsconfig.json with references to package configs and shared compiler options. { 'references': [{ 'path': 'packages/common' }, { 'path': 'packages/client' }] }

What are TypeScript Language Service plugins?

Language Service plugins extend TypeScript's language service functionality. They can add custom type checking, code completion, and refactoring capabilities. Example configuration: { 'compilerOptions': { 'plugins': [{ 'name': 'typescript-styled-plugin' }] } }. Common uses include styled-components integration and custom lint rules.

How do you configure incremental compilation in TypeScript?

Incremental compilation is configured using: 1) incremental flag, 2) tsBuildInfoFile option, 3) composite project setting. Example: { 'compilerOptions': { 'incremental': true, 'tsBuildInfoFile': './buildcache/front-end.tsbuildinfo' } }. This improves build performance by reusing previous compilation results.

What are the different module systems supported by TypeScript?

TypeScript supports multiple module systems: 1) ES Modules (import/export), 2) CommonJS (require/exports), 3) AMD, 4) UMD, 5) System. Configure using the module compiler option. Example: { 'compilerOptions': { 'module': 'esnext', 'moduleResolution': 'node' } }. Choice depends on target environment and compatibility requirements.

How do you configure source maps in TypeScript?

Source maps are configured using: 1) sourceMap compiler option, 2) sourceRoot option, 3) mapRoot option. Example: { 'compilerOptions': { 'sourceMap': true, 'sourceRoot': '/', 'mapRoot': 'dist/maps' } }. They enable debugging TypeScript code directly in browsers or editors.

What are the different ways to handle assets and resources in TypeScript?

Assets can be handled through: 1) Declaration files for non-code assets, 2) Module declarations for imports, 3) Webpack loaders, 4) Custom type definitions. Example: declare module '*.png' { const content: string; export default content; }. This enables type-safe handling of various resource types.

How do you configure TypeScript for testing environments?

Testing configuration includes: 1) Separate tsconfig.test.json, 2) Jest configuration with ts-jest, 3) Test-specific module resolution, 4) Test file patterns. Example: { 'extends': './tsconfig.base.json', 'compilerOptions': { 'types': ['jest'], 'esModuleInterop': true } }. This ensures proper testing setup with TypeScript.

What are the different build modes in TypeScript?

TypeScript supports different build modes: 1) Regular compilation (tsc), 2) Watch mode (tsc -w), 3) Project references build (tsc -b), 4) Incremental builds. Example using build mode: tsc -b src/tsconfig.json --verbose. Each mode serves different development scenarios and requirements.

How do you configure TypeScript for different module bundlers?

Configuration varies by bundler: 1) Webpack: ts-loader or babel-loader, 2) Rollup: @rollup/plugin-typescript, 3) Parcel: Built-in TypeScript support, 4) esbuild: Native TypeScript support. Example Rollup config: import typescript from '@rollup/plugin-typescript'; export default { plugins: [typescript()] }

Explore More

HR Interview Questions

Why Prepare with Stark.ai for typescript Interviews?

Role-Specific Questions

  • Frontend Developer
  • Full-Stack Engineer
  • Software Architect

Expert Insights

  • Detailed explanations of TypeScript's type system and advanced features.

Real-World Scenarios

  • Practical challenges that simulate real-world TypeScript development tasks.

How Stark.ai Helps You Prepare for typescript Interviews

Mock Interviews

Simulate TypeScript-specific interview scenarios.

Explore More

Practice Coding Questions

Solve TypeScript challenges tailored for interviews.

Explore More

Resume Optimization

Highlight your TypeScript expertise with an ATS-friendly resume.

Explore More

Tips to Ace Your typescript Interviews

Master Type Systems

Understand interfaces, generics, unions, and type inference.

Practice Type Design

Work on creating flexible and reusable type definitions.

Learn Advanced Features

Explore decorators, namespaces, and module systems.

Be Ready for Code Reviews

Expect questions about type safety and code organization.

Ready to Ace Your TypeScript Interviews?

Join thousands of successful candidates preparing with Stark.ai. Start practicing TypeScript questions, mock interviews, and more to secure your dream role.

Start Preparing now
practicing