TypeScript Interview Questions and Answers
What is TypeScript? How does it differ from JavaScript?
-
TypeScript is a superset of JavaScript that adds static typing to the language.
- Difference: JavaScript is dynamically typed (type checking happens at runtime), while TypeScript is statically typed (type checking happens at compile time). TypeScript code needs to be compiled into JavaScript to be executed by browsers or Node.js environments.
Why should you use TypeScript? What are its main benefits?
- Early Error Detection: Catches type-related errors during development, reducing runtime bugs.
- Improved Code Readability and Maintainability: Types provide clear documentation and make code easier to understand.
- Enhanced Tooling and IDE Support: Enables features like autocompletion, refactoring, and navigation.
- Better Collaboration: Makes it easier for teams to work on large codebases.
- Safer Refactoring: Allows for changes with more confidence due to type safety.
Explain the concept of Static Typing.
- Static typing means that the type of a variable is checked at compile time, before the code is executed. This allows the compiler to detect type-related errors early in the development process.
What is the TypeScript Compiler (`tsc`)? What is its role?
- The TypeScript Compiler (`tsc`) is the command-line tool used to compile TypeScript code (`.ts` files) into JavaScript code (`.js` files). Its role is to perform type checking and transform the TypeScript syntax into standard JavaScript that can be understood by JavaScript runtimes.
What is `tsconfig.json`? What are some important options?
-
`tsconfig.json` is a configuration file that specifies the root files and compiler options required to compile a TypeScript project. Important options include:
- `target`: The ECMAScript target version for the generated JavaScript code.
- `module`: The module system for the generated JavaScript code.
- `outDir`: The directory where the compiled JavaScript files will be placed.
- `rootDir`: The root directory containing the TypeScript source files.
- `strict`: Enables a set of strict type-checking options (highly recommended).
- `esModuleInterop`: Enables interoperability between CommonJS and ES Modules.
Explain the basic types in TypeScript: `boolean`, `number`, `string`, `array`.
- `boolean`: Represents a boolean value (true or false).
- `number`: Represents both integer and floating-point numbers.
- `string`: Represents textual data.
- `array`: Represents a collection of elements of the same type (e.g., `number[]` or `Array
`).
What is the `any` type? When should you use it? What are its drawbacks?
-
The `any` type allows you to opt out of type checking for a variable. You can assign any value to a variable of type `any`, and you can access any property or call any method on it without compile-time errors.
- When to use: When migrating a JavaScript codebase to TypeScript incrementally, or when dealing with dynamic data from external sources where the structure is unknown.
- Drawbacks: It defeats the purpose of using TypeScript's static typing and eliminates the benefits of compile-time error checking for that variable, potentially leading to runtime errors.
What is the `unknown` type? How is it different from `any`?
-
The `unknown` type represents a value that could be anything, similar to `any`. However, it is safer than `any` because you cannot perform operations on a variable of type `unknown` without first narrowing its type (e.g., using type checking or assertions).
- Difference: `any` allows any operation without checks, while `unknown` requires type narrowing before performing operations.
Explain Type Annotations. How does Type Inference work?
- Type Annotations: Explicitly specifying the type of a variable, function parameter, or return value using a colon followed by the type (e.g.,
).let age: number = 30;
- Type Inference: TypeScript's ability to automatically determine the type of a variable based on the value it is assigned. This reduces the need for explicit type annotations in many cases.
What are Interfaces? What are they used for?
- Interfaces are used to define the shape of objects. They specify the names and types of properties and methods that an object should have. Interfaces are primarily used for type checking and do not generate any JavaScript code at runtime.
What are Type Aliases? How do they differ from Interfaces?
-
Type aliases are used to create a new name for a type. They can represent primitive types, union types, intersection types, tuples, or any other type.
- Difference: Interfaces are specifically for defining object shapes and can be extended and implemented. Type aliases can define any type and are generally more flexible for complex type compositions (like union or intersection types). Interfaces are generally preferred for defining object shapes.
Explain Union Types. Give an example.
-
Union types allow a variable to hold a value that can be one of several specified types. They are defined using the `|` symbol.
let id: number | string; id = 101; id = "abc-123";
Explain Intersection Types. Give an example.
-
Intersection types combine multiple types into a single type, meaning an object of an intersection type must have all properties from all intersected types. They are defined using the `&` symbol.
interface Draggable { drag(): void; } interface Resizable { resize(): void; } type UIElement = Draggable & Resizable; let element: UIElement = { drag: () => {}, resize: () => {} };
What are Literal Types? Give an example.
-
Literal types allow you to specify that a variable can only hold a specific literal value (a string, number, or boolean).
let direction: "up" | "down" | "left" | "right"; direction = "up"; // Valid // direction = "forward"; // Error
Explain the concept of Type Narrowing. Give an example.
-
Type narrowing is the process by which TypeScript infers a more specific type for a variable within a certain code block based on runtime checks. This allows you to safely access properties or methods that are only available on the narrower type.
function printId(id: number | string) { if (typeof id === "string") { console.log(id.toUpperCase()); // TypeScript knows id is a string here } else { console.log(id.toFixed(2)); // TypeScript knows id is a number here } }
What is a Tuple? Give an example.
-
A tuple is a fixed-size array where each element has a specific type. The order and number of elements are important.
let user: [string, number]; user = ["Alice", 30]; // Valid // user = [30, "Alice"]; // Error
What is an Enum? Give an example.
-
An enum (enumeration) is a way to define a set of named constants. They can be numeric or string-based.
enum Direction { Up, Down, Left, Right, } let move: Direction = Direction.Up; console.log(move); // Output: 0 (by default, enums are numeric)
What is the `void` type? When is it used?
-
The `void` type is used to indicate that a function does not return a value.
function logMessage(message: string): void { console.log(message); }
What is the `never` type? When is it used?
-
The `never` type represents the type of values that will never occur. It is typically used for functions that never return (e.g., functions that always throw an exception or enter an infinite loop).
function error(message: string): never { throw new Error(message); }
Explain Function Overloads. Give an example.
-
Function overloads allow you to declare multiple function signatures for a single function implementation. This provides better type checking for functions that can accept different types or numbers of arguments.
function add(a: number, b: number): number; function add(a: string, b: string): string; function add(a: any, b: any): any { return a + b; } const sumNum = add(5, 10); // sumNum is number const sumStr = add("Hello", "World"); // sumStr is string
What are Classes in TypeScript? How do they relate to Interfaces?
- Classes in TypeScript are similar to classes in other object-oriented languages. They provide a blueprint for creating objects with properties and methods. Classes can implement interfaces, which means the class must adhere to the contract defined by the interface.
Explain Access Modifiers (`public`, `private`, `protected`).
- `public` (default): Members are accessible from anywhere.
- `private` (TypeScript only): Members are only accessible within the class itself.
- `protected`: Members are accessible within the class and by instances of derived classes.
What is the difference between `interface` and `type`? (Revisited)
- Interfaces are primarily for defining object shapes, can be extended and implemented by classes, and are generally preferred for object types. Type aliases can define any type (primitives, unions, intersections, tuples, etc.) and are more flexible for complex type compositions. In most cases, you can use either for object shapes, but interfaces are more idiomatic for class implementations and merging declarations.
What are Generics? Why are they useful?
- Generics allow you to write reusable code that can work with a variety of types, providing type safety without sacrificing flexibility. They are useful for creating components, functions, or data structures that can operate on different data types while maintaining type checking.
Give an example of a Generic Function.
function identity(arg: T): T {
return arg;
}
let output1 = identity("myString"); // output1 is string
let output2 = identity(100); // output2 is number
Give an example of a Generic Interface.
interface GenericIdentityFn {
(arg: T): T;
}
function identity(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn = identity;
What are Generic Constraints? Give an example.
-
Generic constraints allow you to restrict the types that can be used with a generic type. This is useful when you need to ensure that the generic type has certain properties or methods.
interface Lengthwise { length: number; } function loggingIdentity
(arg: T): T { console.log(arg.length); // Now we know arg has a .length property return arg; } loggingIdentity("hello"); // Works because string has a .length property // loggingIdentity(3); // Error because number does not have a .length property
Explain Type Assertions. When would you use them?
-
Type assertions are a way of telling the compiler that you know the type of a variable better than it does. You use the
syntax or theas type
syntax (thoughvalue
is preferred in TSX/JSX). You would use them when you are confident about the type of a value based on context that the compiler cannot infer.as type
let someValue: unknown = "this is a string"; let strLength: number = (someValue as string).length;
What are Declaration Files (`.d.ts`)? What is their purpose?
- Declaration files provide type information for existing JavaScript code. They describe the types of variables, functions, classes, etc., in a JavaScript library or module, allowing TypeScript to perform type checking without needing the original source code. Their purpose is to enable using JavaScript libraries in TypeScript projects with type safety.
How do you get type definitions for popular JavaScript libraries?
- Using `@types` packages from npm. These packages are maintained by the DefinitelyTyped community and provide `.d.ts` files for thousands of JavaScript libraries. You install them as dev dependencies (e.g.,
).npm install @types/lodash --save-dev
Explain the concept of Decorators (Experimental). When would you use them?
- Decorators are a special kind of declaration that can be attached to classes, methods, accessors, properties, or parameters. They are functions that are called at declaration time and can modify or add metadata to the decorated element. They are often used for metaprogramming tasks, such as adding logging, validation, or dependency injection (common in frameworks like Angular).
What are Utility Types? Name a few examples.
-
Utility types are built-in generic types that provide transformations on existing types. They help in creating new types based on existing ones in a concise way. Examples:
: Makes all properties of `T` optional.Partial
: Makes all properties of `T` required.Required
: Makes all properties of `T` read-only.ReadOnly
: Constructs a type by picking the set of properties `K` from `T`.Pick
: Constructs a type by omitting the set of properties `K` from `T`.Omit
Explain Conditional Types. Give an example.
-
Conditional types allow you to define types that depend on a condition expressed as a type relationship test (
).T extends U ? X : Y
type IsString
= T extends string ? "yes" : "no"; type Result1 = IsString ; // Result1 is "yes" type Result2 = IsString ; // Result2 is "no"
Explain Mapped Types. Give an example.
-
Mapped types allow you to create new types by iterating over the properties of an existing type and transforming them.
type ReadOnly
= { readonly [P in keyof T]: T[P]; }; interface Person { name: string; age: number; } type ReadOnlyPerson = ReadOnly ; // ReadOnlyPerson is { readonly name: string; readonly age: number; }
What are Index Signatures? When would you use them?
-
Index signatures are used to define the type of properties for objects when the property names are not known in advance, but you know the type of the keys and values. They are useful for objects used as dictionaries or maps.
interface StringDictionary { [key: string]: string; } let myDictionary: StringDictionary = { hello: "world", greeting: "hi", };
How do you configure TypeScript to work with React/JSX?
- Set the
option injsx
to a value liketsconfig.json
,"react"
, or"react-jsx"
. This tells the compiler how to handle JSX syntax."react-native"
How do you configure TypeScript to work with Vue/TSX?
- Set the
option injsx
totsconfig.json
or"preserve"
. You also typically need a build tool (like Vue CLI, Vite, or Webpack) configured to handle `.vue` files and TSX."vue-jsx"
What is the purpose of the `strict` compiler option?
- The
option is a convenient shorthand that enables a set of recommended strict type-checking options, includingstrict
,noImplicitAny
,noImplicitThis
,strictNullChecks
,strictFunctionTypes
, andstrictPropertyInitialization
. EnablingnoImplicitReturns
mode is highly recommended for better type safety.strict
Explain `strictNullChecks`. What problem does it solve?
preventsstrictNullChecks
andnull
from being assigned to variables unless you explicitly declare that the variable can beundefined
ornull
using a union type (e.g.,undefined
). It solves the problem of "null pointer exceptions" or "undefined is not a function" errors that are common in JavaScript.string | null | undefined
What is the purpose of `noImplicitAny`?
flags variables, function parameters, or return values that TypeScript cannot infer a type for as having an implicitnoImplicitAny
type. This encourages you to explicitly provide type annotations and avoid accidentally opting out of type checking.any
What is the purpose of `noImplicitThis`?
flagsnoImplicitThis
expressions with an impliedthis
type. This helps ensure thatany
is correctly typed in functions and methods, especially when working with callbacks or event handlers.this
Explain Module Resolution in TypeScript.
- Module resolution is the process by which TypeScript figures out which file a module import refers to. It follows different strategies (like Node.js or Classic) to locate the module file based on the import path and the configured module system.
What is the difference between `export default` and `export`?
: Exports a single default member from a module. It is imported without curly braces. There can only be one default export per module.export default
: Exports named members from a module. They are imported using curly braces, matching the name used in the export. A module can have multiple named exports.export
How do you provide type information for a JavaScript library that doesn't have `.d.ts` files?
- You can write your own `.d.ts` file that describes the library's API. You can also contribute to the DefinitelyTyped project to add type definitions for the library.
What is the purpose of the `paths` option in `tsconfig.json`?
- The
option allows you to define module aliases, mapping import paths to specific directories. This is useful for creating cleaner import statements (e.g.,paths
instead of a relative path) and for working with monorepos.import { Button } from '@components/Button';
How do you set up Linting and Formatting for TypeScript?
- Install ESLint and its TypeScript plugin (
,@typescript-eslint/eslint-plugin
).@typescript-eslint/parser
- Configure ESLint rules in a
or.eslintrc.js
file..eslintrc.json
- Install Prettier and its ESLint integration (
,eslint-config-prettier
).eslint-plugin-prettier
- Configure Prettier options in a
or.prettierrc.js
file..prettierrc.json
How do you test TypeScript code?
- Use testing frameworks like Jest, Mocha, or Vitest. You typically need to configure a preprocessor (like
orts-jest
) to compile TypeScript code before running tests.@vitest/ui
What are Source Maps? Why are they important for debugging TypeScript?
- Source maps are files that map locations in the compiled JavaScript code back to their corresponding locations in the original TypeScript source code. They are important for debugging because they allow you to set breakpoints and inspect variables in your original TypeScript code within the browser or Node.js debugger, even though the code being executed is JavaScript.
What is the difference between `interface` and `class`?
: Defines a contract for the shape of an object. It only exists at compile time and does not generate any JavaScript code.interface
: Provides a blueprint for creating objects with properties and methods. It exists at both compile time and runtime (compiled to a JavaScript class or function). Classes can implement interfaces.class
Can you extend a class and implement an interface simultaneously? Give an example.
-
Yes. A class can extend another class to inherit its properties and methods, and it can also implement one or more interfaces to adhere to their contracts.
class Animal { name: string; constructor(name: string) { this.name = name; } move(distance: number = 0) { console.log(`${this.name} moved ${distance}m.`); } } interface Speakable { speak(): void; } class Dog extends Animal implements Speakable { constructor(name: string) { super(name); } speak() { console.log("Woof!"); } } let myDog = new Dog("Buddy"); myDog.move(10); myDog.speak();
What is the purpose of the `readonly` modifier?
- The
modifier can be applied to properties in interfaces or classes to indicate that the property can only be assigned a value during initialization (or within the constructor for classes) and cannot be modified afterwards.readonly
What is the difference between `const` and `readonly`?
: Applies to variables and prevents reassignment of the variable itself. The value it points to can still be mutable (e.g., modifying an array or object).const
: Applies to properties of objects or classes and prevents modification of the property's value after initialization. The variable holding the object can still be reassigned if it's not declared withreadonly
.const
Explain the concept of Type Guards.
- Type guards are special functions or expressions that perform runtime checks to narrow the type of a variable within a specific scope. They are used to tell the compiler more specific type information than it can infer on its own. Common type guards include
,typeof
,instanceof
, and user-defined type guard functions (in
).arg is Type
Give an example of a User-Defined Type Guard.
-
A user-defined type guard is a function that returns a boolean and whose return type is a type predicate (
).parameterName is Type
interface Fish { swim(): void; fin: number; } interface Bird { fly(): void; wing: number; } function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined; } function move(pet: Fish | Bird) { if (isFish(pet)) { pet.swim(); // TypeScript knows pet is a Fish here } else { pet.fly(); // TypeScript knows pet is a Bird here } }
What are Discriminant Unions? How do they help with type narrowing?
-
Discriminant unions are a pattern for working with union types where each member of the union has a common literal property (the discriminant) that can be used to uniquely identify the type of the object. By checking the value of the discriminant property, TypeScript can narrow down the type of the object within a conditional block.
interface Square { kind: "square"; size: number; } interface Circle { kind: "circle"; radius: number; } type Shape = Square | Circle; function area(s: Shape) { if (s.kind === "square") { return s.size * s.size; // TypeScript knows s is a Square } else { return Math.PI * s.radius ** 2; // TypeScript knows s is a Circle } }
What is the purpose of the `!` (non-null assertion operator)? When should you use it?
- The
operator is a non-null assertion operator. It tells the compiler that you are certain that a value is not!
ornull
, even if TypeScript's type checking doesn't guarantee it. You should use it sparingly and only when you have external knowledge that the value is indeed non-null, as it bypasses type safety and can lead to runtime errors if your assumption is wrong.undefined
What is the purpose of the `?` (optional chaining operator)?
- The
operator is the optional chaining operator. It allows you to safely access properties or call methods on an object that might be null or undefined. If the part before the?
is null or undefined, the expression short-circuits and returns?
instead of throwing an error.undefined
What is the purpose of the `??` (nullish coalescing operator)?
- The
operator is the nullish coalescing operator. It provides a default value for an expression if the expression evaluates to??
ornull
. It is similar to theundefined
operator but only checks for||
andnull
, not other falsy values likeundefined
,0
, or""
.false
Explain the concept of Decorator Factories.
- A decorator factory is a function that returns a decorator. This allows you to configure the decorator with arguments when you apply it. Decorator factories are commonly used when you need to pass data to a decorator.
What is the difference between `type` and `interface` when it comes to declaration merging?
- Interfaces support declaration merging, meaning if you declare an interface with the same name multiple times, TypeScript will merge their definitions into a single interface. Type aliases do not support declaration merging; declaring a type alias with the same name multiple times will result in a duplicate identifier error.
How do you handle asynchronous operations and Promises in TypeScript?
- Using the
type, wherePromise
is the type of the value the promise resolves with.T
- Using
/async
with proper type annotations for function return types (await
).Promise
How do you type a function that takes a callback?
-
You define the function signature for the callback function as a parameter type.
function fetchData(callback: (data: string) => void): void { // ... fetch data callback("Some data"); }
How do you type an event handler in TypeScript?
-
Use the built-in event types provided by TypeScript (e.g.,
,MouseEvent
,KeyboardEvent
) or define custom event types if needed.ChangeEvent
function handleClick(event: React.MouseEvent
): void { // ... } function handleChange(event: React.ChangeEvent ): void { // ... }
What is the purpose of the `as const` assertion?
- The
assertion is used to tell TypeScript to infer the narrowest possible type for a literal value (e.g., a string literal as its literal type, an array as a tuple with readonly elements, an object with readonly properties). It makes the literal value immutable and its type more specific.as const
Explain the concept of Structural Typing vs. Nominal Typing. How does TypeScript relate?
- Structural Typing: A type is compatible with another if it has the same structure (properties and methods), regardless of its name or origin.
- Nominal Typing: A type is compatible with another only if they have the same name, even if they have the same structure.
- TypeScript: TypeScript is primarily a structurally typed language. This means that if two interfaces or types have the same shape, they are considered compatible.
What are Type Inference Limits? When might you need explicit annotations?
-
While TypeScript's type inference is powerful, it has limits. You might need explicit type annotations in cases like:
- Variables declared without an initial value.
- Function parameters (unless they have default values).
- Complex return types in functions.
- When you want to ensure a specific type for clarity or stricter checking.
How do you handle errors in TypeScript?
- Using
blocks. The type of the caught error istry...catch
by default (in strict mode) and needs to be narrowed.unknown
- Defining custom error classes that extend
.Error
What is the purpose of the `exclude` and `include` options in `tsconfig.json`?
: Specifies an array of file patterns to include in the compilation.include
: Specifies an array of file patterns to exclude from the compilation.exclude
- These options control which files are considered part of your TypeScript project.
What is the purpose of the `noEmit` option in `tsconfig.json`?
prevents the compiler from emitting JavaScript files. This is useful when you are only using TypeScript for type checking and relying on another tool (like Babel or Webpack) to handle the compilation.noEmit
What is the purpose of the `esModuleInterop` option?
enables a compatibility layer to make importing CommonJS modules from ES Modules in TypeScript work more smoothly. It adds helper code to the compiled JavaScript to handle differences in module systems.esModuleInterop
How do you use TypeScript with Webpack?
- Use a loader like
orts-loader
with the TypeScript preset. Configure Webpack to handle `.ts` and `.tsx` files.babel-loader
How do you use TypeScript with Babel?
- Use the
preset. Babel will strip out the type annotations, and you still rely on the TypeScript compiler for type checking (often done separately or as part of a build process).@babel/preset-typescript
What is the difference between `tsc` and Babel for compiling TypeScript?
: Performs both type checking and compilation.tsc
- Babel: Only performs compilation (transpilation), stripping out type annotations. You still need
for type checking. Babel is often faster for compilation but doesn't provide type safety during the process.tsc
What are Triple-Slash Directives? When would you use them?
- Triple-slash directives are single-line comments at the top of a TypeScript file that provide instructions to the compiler. Examples include
(to declare a dependency on another `.d.ts` file) and///
. They are less common now with ES Module imports.///
Explain the concept of Ambient Modules. When would you use them?
- Ambient modules are used to declare types for modules that are not written in TypeScript (e.g., JavaScript libraries) and don't have `.d.ts` files. You would use them to create a type definition for a module when `@types` is not available or when you need to provide a custom type definition.
What is the purpose of the `declare` keyword?
- The
keyword is used to tell the TypeScript compiler that a variable, function, class, or module exists elsewhere (usually in JavaScript code) and provides its type signature without providing an implementation. It's used in `.d.ts` files or when writing ambient declarations.declare
What is the difference between `interface` and `abstract class`?
: Defines a contract for object shape, no implementation, exists only at compile time.interface
: A class that cannot be instantiated directly but can be extended. Can contain abstract methods (must be implemented by subclasses) and concrete methods/properties. Exists at both compile time and runtime.abstract class
Can a TypeScript interface have optional methods?
-
Yes, similar to optional properties, you can mark methods as optional using the
operator.?
interface MyInterface { requiredMethod(): void; optionalMethod?(): void; }
How do you type a function that accepts an object with arbitrary string keys and number values?
-
Using an index signature:
interface NumberMap { [key: string]: number; } function processMap(data: NumberMap): void { // ... }
What is the purpose of the `keyof` type operator? Give an example.
-
The
operator takes an object type and produces a union type of its property names (as string literals).keyof
interface Person { name: string; age: number; } type PersonKeys = keyof Person; // PersonKeys is "name" | "age"
What is the purpose of the `typeof` type operator? Give an example.
-
The
operator in a type context takes an expression and produces the type of that expression.typeof
let s = "hello"; let n: typeof s; // n is string
What is the difference between `typeof` in JavaScript and `typeof` in TypeScript?
- JavaScript
: A runtime operator that returns a string indicating the primitive type of a value.typeof
- TypeScript
: A type operator that returns the type of an expression at compile time.typeof
Explain the concept of Type Compatibility.
- Type compatibility in TypeScript is based on structural subtyping. Type A is compatible with Type B if Type A has at least all the members of Type B, and the corresponding members are compatible.
What is Excess Property Checking? When does it occur?
- Excess property checking is a feature in TypeScript that warns you when you assign an object literal to a type that doesn't have all the properties of the object literal, even if the object literal has all the properties required by the type. It helps catch typos or incorrect property names. It occurs when assigning object literals directly.
How can you bypass Excess Property Checking?
- Assign the object literal to a variable first.
- Use a type assertion (
).as Type
- Add an index signature to the type.
What is the purpose of the `satisfies` operator (TypeScript 4.9+)?
- The
operator allows you to validate that an expression satisfies a certain type without affecting the inferred type of the expression. This is useful when you want to ensure an object conforms to an interface while still allowing the compiler to infer the most specific literal types for its properties.satisfies
How do you handle potential runtime errors in TypeScript?
- Even with static typing, runtime errors can occur (e.g., network failures, invalid data from external sources, logic errors). You handle them using standard JavaScript error handling mechanisms like
and by implementing robust error handling logic in your application code. TypeScript helps prevent *type-related* runtime errors.try...catch
What are some common TypeScript compiler errors you might encounter?
(Missing declaration).TS2304: Cannot find name '...'
.TS2322: Type '...' is not assignable to type '...'
.TS2339: Property '...' does not exist on type '...'
.TS2532: Object is possibly 'undefined'
.TS2533: Object is possibly 'null'
.TS7006: Parameter '...' implicitly has an 'any' type.
How do you debug TypeScript code in VS Code?
- Ensure you have a
file configured.launch.json
- Set breakpoints in your `.ts` files.
- Run your application with the debugger attached.
- Use source maps to map back to the original TypeScript code.
What is the difference between `null` and `undefined` in TypeScript? (Revisited in the context of `strictNullChecks`)
: Represents the intentional absence of any object value.null
: Indicates that a variable has been declared but has not yet been assigned a value.undefined
- With
, they are treated as distinct types and cannot be assigned to a variable of a non-nullable type unless explicitly included in a union type.strictNullChecks
How do you define a type for a function that takes a variable number of arguments?
-
Using rest parameters with an array type:
function sum(...numbers: number[]): number { return numbers.reduce((acc, num) => acc + num, 0); }
What is the purpose of the `infer` keyword in conditional types?
- The
keyword is used within a conditional type to declare a new type variable that can "infer" a type from the type being tested. This allows you to extract parts of a type and use them in the resulting type.infer
Give an example using `infer`.
type ReturnType = T extends (...args: any[]) => infer R ? R : any;
function greet(): string {
return "Hello";
}
type GreetingReturnType = ReturnType; // GreetingReturnType is string
What is the purpose of the `required` and `optional` modifiers in mapped types?
/+required
: Adds or removes the-required
modifier from properties.required
/+optional
: Adds or removes the-optional
modifier from properties.optional
- These are used within mapped types to change the optionality of properties.
What is the purpose of the `readonly` and `writable` modifiers in mapped types?
/+readonly
(or-readonly
): Adds or removes thewritable
modifier from properties.readonly
- These are used within mapped types to change the mutability of properties.
How do you type a class constructor?
- You can't directly type the constructor itself like a regular function. The types of the constructor parameters are defined within the class definition.
- When referencing the constructor's signature, you typically refer to the class type itself.
What is the purpose of the `abstract` keyword on a class or method?
on a class means the class cannot be instantiated directly.abstract
on a method within an abstract class means the method has no implementation in the abstract class and must be implemented by any non-abstract derived class.abstract
What are Mixins in TypeScript? How are they implemented?
- Mixins are a way to compose classes by combining partial class implementations. They are implemented using a mixin function that takes a base class and returns a new class that extends the base class and adds the mixin's functionality.
What are Type Predicates? (Revisited)
- Type predicates are a special form of return type annotation for functions (
) that signal to the compiler that if the function returns true, the parameter has been narrowed to the specified type.parameterName is Type
How do you type a variable that can be either a specific value or null/undefined?
- Using a union type with
and/ornull
:undefined
orlet name: string | null;
orlet age: number | undefined;
.let value: string | null | undefined;
What is the purpose of the `noUnusedLocals` and `noUnusedParameters` options in `tsconfig.json`?
: Reports errors on unused local variables.noUnusedLocals
: Reports errors on unused function parameters.noUnusedParameters
- These options help keep your codebase clean and avoid potential bugs from unused code.
What is the purpose of the `noFallthroughCasesInSwitch` option?
reports errors on switch statements that have non-empty case clauses without anoFallthroughCasesInSwitch
statement. This helps prevent unintentional fallthrough between cases.break
What is the purpose of the `forceConsistentCasingInFileNames` option?
ensures that file names are consistent in casing across different operating systems, which can prevent issues related to case-sensitive file systems.forceConsistentCasingInFileNames
What is the purpose of the `strictBindCallApply` option?
enables stricter checking for thestrictBindCallApply
,bind
, andcall
methods on functions, ensuring that they are called with the correct arguments.apply
What is the purpose of the `strictPropertyInitialization` option?
ensures that class properties declared without an initializer are assigned a value in the constructor.strictPropertyInitialization
What is the purpose of the `noImplicitReturns` option?
reports errors on functions that don't always return a value on every possible code path, ensuring that functions that are supposed to return a value do so consistently.noImplicitReturns
What is the purpose of the `skipLibCheck` option?
skips type checking of declaration files (`.d.ts`). This can speed up compilation, but it means you won't catch type errors within the libraries you are using.skipLibCheck
What is the purpose of the `esModuleInterop` option? (Revisited)
- To enable compatibility between CommonJS and ES Modules when importing.
How do you use TypeScript with npm packages?
- Install the package using npm or yarn.
- If the package includes its own type definitions, TypeScript will automatically pick them up.
- If the package does not include type definitions, install the corresponding `@types` package from npm (e.g.,
).npm install @types/library-name --save-dev
- Import the package in your TypeScript code.
What is the difference between `import type` and `import`? (TypeScript 3.8+)
: Imports only type declarations. This import is completely erased at runtime and does not generate any JavaScript code. Useful for preventing unnecessary imports in the output JavaScript.import type
: Imports both type declarations and runtime values. Generates JavaScript code.import
What are Const Assertions? (Revisited)
is a const assertion. It tells TypeScript to infer the narrowest possible literal types and make them readonly.as const
What is the purpose of the `satisfies` operator? (Revisited)
- To validate an expression against a type without affecting its inferred type.
How do you type a function that returns a Promise that resolves with a specific type?
-
Using
as the return type:Promise
async function fetchData(): Promise
{ // ... fetch data return "data"; }
How do you type an object with optional properties?
-
Using the
modifier on the property name in an interface or type alias:?
interface User { id: number; name: string; email?: string; // Optional property }
How do you type an object with read-only properties?
-
Using the
modifier on the property name in an interface or type alias:readonly
interface Config { readonly apiUrl: string; readonly timeout: number; }
What is the difference between an `enum` and a union of literal types?
: Creates a runtime object with named constants. Can be numeric or string-based.enum
- Union of literal types: Exists only at compile time for type checking. Does not create a runtime object.
- For simple sets of string values, a union of literal types is often preferred as it has no runtime overhead.
What is the purpose of the `target` compiler option? (Revisited)
- Specifies the ECMAScript version that the compiled JavaScript code should target. This affects which JavaScript features can be used directly and which need to be transpiled.
What is the purpose of the `module` compiler option? (Revisited)
- Specifies the module system to use in the compiled JavaScript code (e.g., CommonJS, ESNext, AMD).
What is the purpose of the `outDir` compiler option? (Revisited)
- Specifies the output directory for the compiled JavaScript files.
What is the purpose of the `rootDir` compiler option? (Revisited)
- Specifies the root directory containing the TypeScript source files. Used to determine the directory structure of the output files when
is specified.outDir
What is the purpose of the `declaration` compiler option?
generates corresponding `.d.ts` files for your TypeScript files when compiling. This is useful when creating libraries that will be used by other TypeScript projects.declaration: true
What is the purpose of the `sourceMap` compiler option?
generates source map files (`.js.map`) alongside the compiled JavaScript files. Essential for debugging.sourceMap: true
What is the purpose of the `allowJs` compiler option?
allows JavaScript files to be included in your TypeScript project and processed by the compiler (e.g., for linting or bundling).allowJs: true
What is the purpose of the `checkJs` compiler option?
enables type checking for JavaScript files in your project. This can help improve the reliability of your JavaScript code even without fully migrating to TypeScript.checkJs: true
What is the purpose of the `noEmitOnError` compiler option?
prevents the compiler from emitting JavaScript files if there are any type errors. This ensures that you only build and deploy code that is type-safe.noEmitOnError: true
What is the purpose of the `isolatedModules` compiler option?
ensures that each file can be safely compiled without relying on type information from other files. This is required by some build tools (like esbuild or swc) that compile files in isolation.isolatedModules: true
What is the purpose of the `strictFunctionTypes` option?
enables stricter checking for function types, specifically for parameters. It ensures that function parameters are contravariantly typed, which is the correct behavior for function subtyping.strictFunctionTypes
What is the purpose of the `strictPropertyInitialization` option? (Revisited)
- Ensures class properties are initialized in the constructor.
What is the purpose of the `noImplicitReturns` option? (Revisited)
- Reports errors for functions that don't always return a value.
What is the purpose of the `noFallthroughCasesInSwitch` option? (Revisited)
- Reports errors on switch statements without
.break
What is the purpose of the `forceConsistentCasingInFileNames` option? (Revisited)
- Ensures consistent file name casing.
What is the purpose of the `skipLibCheck` option? (Revisited)
- Skips type checking of declaration files.
How do you handle circular dependencies with types?
- In many cases, TypeScript can handle circular dependencies between types correctly as long as the types are not directly dependent on each other in a way that prevents the compiler from resolving them. If you encounter issues, you might need to refactor your types or use techniques like forward declarations (less common in modern TS).
What is the purpose of the `namespace` keyword? (Less common in modern TS)
is used to group related code (types, functions, etc.) and prevent naming conflicts. It was more common before ES Modules became widely adopted. It generates JavaScript code that creates nested objects.namespace
What is the difference between `namespace` and `module` (ES Modules)?
: Used for internal code organization within a single file or across multiple files that are compiled together. Creates a runtime object.namespace
(ES Modules): Standard way to organize code into separate files with explicit imports and exports. Does not create a single global object. Generally preferred in modern TypeScript development.module
What is the purpose of the `lib` compiler option?
specifies which built-in API declaration files should be included in the compilation. This determines which global APIs (likelib
,DOM
,ESNext
) are available for type checking.Window
How do you define a type for a function that can accept either a single value or an array of values?
-
Using a union type for the parameter:
function processInput(input: string | string[]): void { if (Array.isArray(input)) { // input is string[] } else { // input is string } }
What is the purpose of the `target` and `lib` options working together?
determines the syntax features that are preserved or transpiled.target
determines the global types that are available. For example, settinglib
totarget
and"es5"
tolib
means you can use ES2015 features in your code, but TypeScript will transpile them to ES5, and you will have access to ES2015 global types like"es2015"
.Promise
How do you type an object that has a specific set of known properties and also allows any additional properties with a specific type?
-
Combine known properties with an index signature:
interface User { id: number; name: string; [key: string]: any; // Allows any additional properties }
What is the difference between `any` and `{}`?
: Opts out of type checking entirely. You can access any property or call any method.any
: Represents an object with no properties. You cannot access properties on it without type assertions or narrowing. It's a slightly safer alternative to{}
for indicating "an object of unknown structure."any
What is the purpose of the `never` type in a union?
- When
is part of a union type, it effectively disappears from the union. This is useful in conditional types or when narrowing types to ensure that all possible cases are handled (exhaustive checking).never
How do you use TypeScript with a monorepo?
- Use project references in
to define dependencies between different packages within the monorepo. This allows TypeScript to efficiently build and type-check dependencies.tsconfig.json
What is the purpose of the `references` option in `tsconfig.json`?
- The
option is used in monorepos to define project dependencies between differentreferences
files. This enables features like incremental builds and more efficient type checking across packages.tsconfig.json
What is the purpose of the `composite` compiler option?
indicates that acomposite: true
file is part of a composite project, which is required when using project references. It enables options necessary for incremental builds and project dependencies.tsconfig.json
What is the purpose of the `declarationMap` compiler option?
generates source maps for `.d.ts` files. This allows you to debug type definitions themselves.declarationMap: true
What is the purpose of the `incremental` compiler option?
tells the compiler to save information about the project graph from the last compilation. This allows subsequent compilations to be faster by only recompiling files that have changed.incremental: true
What is the purpose of the `tsbuildinfo` file?
- The
file is generated when the.tsbuildinfo
orincremental
compiler options are enabled. It stores information about the compilation state to enable incremental builds and project references.composite
How do you handle versioning of type definitions in a large project?
- Using project references in a monorepo structure helps manage dependencies and type versions between packages.
- Carefully managing dependencies on `@types` packages and ensuring compatibility with the corresponding library versions.