Top Typescript Interview Questions And Answers (2023)

1.
What is TypeScript and how is it different from JavaScript?
TypeScript is an open-source programming language developed and maintained by Microsoft. It is a superset of JavaScript, which means that any valid JavaScript code is also valid TypeScript code
TypeScript adds static typing, along with additional language features, on top of JavaScript to enhance the development experience
Equivalent example in JavaScript:
2. Language Features: TypeScript includes many features that JavaScript does not have, such as classes (ES6 also have classes but without public, protected,private modifiers), interfaces, enums, and modules. These features enable better code organization, encapsulation, and maintainability.
Example in TypeScript:
Equivalent example in JavaScript (without interfaces and classes):
3. Tooling and Ecosystem: TypeScript has its own compiler (`tsc`) that transpiles TypeScript code into JavaScript, providing additional checks and optimizations. TypeScript integrates well with popular development tools and has a rich ecosystem of libraries and frameworks.
4. Compatibility: Since TypeScript is a superset of JavaScript, any valid JavaScript code is also valid TypeScript code. This allows you to gradually introduce TypeScript into existing JavaScript projects without needing to rewrite the entire codebase.
Conclusion :
TypeScript offers advantages in terms of type safety, code organization, and tooling, while JavaScript provides simplicity and broader browser compatibility. The choice between the two depends on the specific project requirements and developer preferences.
TypeScript and JavaScript are both programming languages used for web development, but there are some key differences between them. Here are a few notable differences with examples:
1. Static Typing: TypeScript is a statically typed superset of JavaScript, which means it supports static typing. In TypeScript, you can declare the types of variables, function parameters, and return types. This allows for better code quality, early error detection, and improved code documentation. Example in TypeScript:
function addNumbers(a: number, b: number): number {
return a + b;
}
const result: number = addNumbers(5, 10);
console.log(result); // Output: 15
function addNumbers(a, b) {
return a + b;
}
const result = addNumbers(5, 10);
console.log(result); // Output: 15
interface Person {
name: string;
age: number;
}
class Employee implements Person {
name: string;
age: number;
id: number;
constructor(name: string, age: number, id: number) {
this.name = name;
this.age = age;
this.id = id;
}
getDetails(): string {
return `Name: ${this.name}, Age: ${this.age}, ID: ${this.id}`;
}
}
const employee = new Employee("John Doe", 30, 12345);
console.log(employee.getDetails()); // Output: Name: John Doe, Age: 30, ID: 12345
const employee = {
name: "John Doe",
age: 30,
id: 12345,
getDetails: function() {
return `Name: ${this.name}, Age: ${this.age}, ID: ${this.id}`;
}
};
console.log(employee.getDetails()); // Output: Name: John Doe, Age: 30, ID: 12345
2.
What are the benefits of using TypeScript?
There are several benefits to using TypeScript for developing web applications:
1. Type Safety: TypeScript introduces static typing to JavaScript, which helps catch errors at compile time rather than at runtime. This improves code reliability and makes it easier to maintain, especially in larger projects with many developers.
2. Code Readability: By adding type annotations, interfaces, and other language constructs, TypeScript makes code more self-documenting and easier to understand. This is especially useful for team collaboration and code reviews.
3. Tooling Support: The TypeScript compiler provides powerful tooling support, including code completion, syntax highlighting, and error highlighting. This helps developers write code faster and with fewer errors.
4. ECMAScript Compatibility: TypeScript is a superset of JavaScript, so all valid JavaScript code is also valid TypeScript code. This means developers can gradually adopt TypeScript into an existing codebase without rewriting everything from scratch.
5. Scalability: TypeScript was designed with scalability in mind, and includes language constructs like modules, namespaces, and classes that are essential for building large-scale applications. TypeScript also supports gradual typing, which allows developers to incrementally add type annotations to a codebase as it grows.
6. Community Support: TypeScript has a large and active community of developers, which means there are many resources available, including documentation, libraries, and tools.
Overall, using TypeScript can help improve code quality, reduce errors, and increase developer productivity, especially in larger projects.
3.
How do you declare a variable in TypeScript?
In TypeScript, you can declare a variable using the `let` or `const` keyword, just like in JavaScript. However, TypeScript also allows you to specify the variable type using type annotations.
Here are a few examples:
In the first example, we declare a variable `myNumber` of type `number` and assign it the value `42`. In the second example, we declare a variable `myString` and TypeScript infers its type to be `string` based on the value `"Hello, world!"`.
In the third example, we declare a constant `PI` of type `number` and assign it the value `3.14`.
In the fourth example, we declare a variable `myArray` of type `string[]`, which is an array of strings. We initialize it with an array of string values.
In the fifth example, we declare a variable `myObject` with an object type that has two properties: `name` of type `string` and `age` of type `number`. We initialize it with an object that has these properties and their corresponding values.
Note that in TypeScript, you can also declare variables using the `var` keyword, but it's generally recommended to use `let` or `const` instead, as they have more predictable scoping rules.
// Declaring a variable with a type annotation
let myNumber: number = 42;
// Declaring a variable without a type annotation
let myString = "Hello, world!";
// Declaring a constant with a type annotation
const PI: number = 3.14;
// Declaring a variable with an array type
let myArray: string[] = ["apple", "banana", "orange"];
// Declaring a variable with an object type
let myObject: { name: string, age: number } = { name: "Alice", age: 30 };
4.
What is a union type in TypeScript?
In TypeScript, a union type allows a variable to have more than one possible type. It is defined using the vertical bar `|` to separate the different types that are allowed. For example:
This declaration specifies that `myVariable` can be either a `number` or a `string`. This can be useful in situations where a function or method can accept arguments of multiple types.
Here's an example of a function that accepts a union type as a parameter:
In this example, the `printId` function accepts an argument of type `number | string`, which means it can accept either a `number` or a `string` as its parameter. The function then simply logs the value of the `id` parameter to the console.
Union types can be combined with other TypeScript features like type guards and conditional types to write more complex and robust code.
let myVariable: number | string;
function printId(id: number | string) {
console.log(`ID is ${id}`);
}
printId(101); // Output: ID is 101
printId("abc"); // Output: ID is abc
5.
How do you define an interface in TypeScript?
In TypeScript, an interface defines the structure of an object. It specifies the names and types of properties that an object must have. To define an interface, you use the `interface` keyword, followed by the interface name and the property definitions enclosed in braces `{ }`. Here's an example:
In this example, we define an interface called `Person` that has four properties: `firstName` and `lastName`, both of type `string`, `age` of type `number`, and an optional property `email` of type `string`.
To use an interface, you can define an object that conforms to its structure:
Here, we define an object `person` that conforms to the `Person` interface. It has properties `firstName`, `lastName`, `age`, and `email`.
If an object doesn't have all the required properties defined in an interface, TypeScript will generate an error:
You can also use interfaces as types for function parameters and return values:
Here, the `getFullName` function takes a parameter of type `Person` and returns a string.
Interfaces can also extend other interfaces and define optional and readonly properties, among other things.
interface Person {
firstName: string;
lastName: string;
age: number;
email?: string;
}
let person: Person = {
firstName: "John",
lastName: "Doe",
age: 30,
email: "john.doe@example.com"
};
let person: Person = {
firstName: "John",
age: 30 // Error: Property 'lastName' is missing
};
function getFullName(person: Person): string {
return `${person.firstName} ${person.lastName}`;
}
6.
How do you use generics in TypeScript?
In TypeScript, generics allow you to create functions, classes, and interfaces that can work with a variety of types rather than a single specific type. This makes your code more reusable and flexible.
To use generics in TypeScript, you use the angle bracket notation `< >` to define a placeholder type that will be replaced with a concrete type when the code is used. Here's an example of a simple generic function that returns the first element of an array:
In this example, the function is defined with the generic type parameter `T`, which is used to declare the type of the array. The function returns the first element of the array, which has the same type as the elements in the array.
To use this function, you call it with an array of a specific type:
Here, the `numbers` array has the type `number[]`, so the generic type parameter `T` in the `getFirst` function is inferred as `number`. The return value of the function is `number | undefined`, which means it can be either a number or undefined if the array is empty.
You can also explicitly specify the type parameter when calling the function:
In this case, the generic type parameter `T` is explicitly set to `string`, so the return value of the function is `string | undefined`.
Generics can also be used with classes and interfaces to create generic types that can work with a variety of types. For example, here's a simple interface that defines a generic `Box` type:
This interface defines a `Box` type that has a single property `value` of type `T`. When you create an instance of `Box`, you can specify the concrete type of `T`:
In this example, `numberBox` has the type `Box` and `stringBox` has the type `Box`.
function getFirst(arr: T[]): T | undefined {
return arr.length > 0 ? arr[0] : undefined;
}
let numbers: number[] = [1, 2, 3];
let firstNumber = getFirst(numbers);
let strings: string[] = ["foo", "bar", "baz"];
let firstString = getFirst(strings);
interface Box {
value: T;
}
let numberBox: Box = { value: 42 };
let stringBox: Box = { value: "hello" };
7.
What is a namespace in TypeScript, and how can you use it?
In TypeScript, a namespace is a way to group related code together and prevent naming conflicts. It is similar to a module in that it can contain functions, classes, and other code, but it is primarily used for organizing code that doesn't need to be exported.
To use a namespace in TypeScript, you can define it using the `namespace` keyword, followed by the namespace name and a block of code containing the definitions of its members. For example:
In this example, we define a namespace called `MyNamespace` that contains a function called `myFunction` and a class called `MyClass`. We also use the `export` keyword to make these members accessible outside of the namespace.
To use the members of a namespace, you can reference them using the namespace name followed by a dot notation. For example:
In this example, we call the `myFunction` function and create an instance of the `MyClass` class, both using the `MyNamespace` prefix.
Using namespaces can help organize your code and prevent naming conflicts, especially when working on large projects with multiple developers. However, it is important to use them judiciously and not create too many layers of nesting, which can make the code harder to read and maintain.
namespace MyNamespace {
export function myFunction() {
// code here
}
export class MyClass {
// code here
}
}
MyNamespace.myFunction();
const myInstance = new MyNamespace.MyClass();
8.
How can you use decorators in TypeScript?
In TypeScript, decorators provide a way to add metadata or behavior to classes, methods, properties, and other declarations at design time. Decorators are applied using the `@` symbol followed by the decorator function name, which can be defined separately.
To create a custom decorator in TypeScript, you can follow these steps:
Step 1: Define the Decorator Function
Start by defining a function that will serve as your decorator. This function will receive the target (class, property, or method) and any additional arguments you want to pass to the decorator. The decorator function should return a modified version of the target or perform any desired actions.
Here's an example of a decorator function that logs a message before and after invoking a method:
Step 2: Apply the Decorator
Now you can apply the decorator to a class, property, or method. To apply the decorator, use the `@` symbol followed by the decorator function name.
Here's an example of applying the `logMethod` decorator to a class method:
In this example, whenever the `greet` method is called, the decorator will log the method name and its arguments before executing the original method. Afterward, it will log the returned value.
Step 3: Use the Decorated Class or Method
You can now use the decorated class or its methods as usual. When you invoke the decorated method, the decorator's logic will be executed alongside the original method's logic.
Output:
That's it! We have successfully created and applied a custom decorator in TypeScript. Decorators provide a powerful way to add behavior to classes, properties, or methods without modifying their implementation directly.
Conclusion:
Using decorators can help you write more expressive and modular code in TypeScript, You can apply decorators to various components and have them automatically execute specific code before, after, or around the execution of the target component. This promotes modular and maintainable code architectures
function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyKey} with arguments:`, ...args);
const result = originalMethod.apply(this, args);
console.log(`Method ${propertyKey} returned:`, result);
return result;
};
return descriptor;
}
class Example {
@logMethod
greet(name: string) {
return `Hello, ${name}!`;
}
}
const instance = new Example();
instance.greet('John');
Calling greet with arguments: John
Method greet returned: Hello, John!
9.
How can you use the "public", "private", and "protected" modifiers in TypeScript?
In TypeScript, you can use the `public`, `private`, and `protected` modifiers to control the visibility and accessibility of class members (properties and methods). These modifiers determine whether a member can be accessed from outside the class, or only from within the class or its subclasses.
- public: A `public` member can be accessed from anywhere, both within and outside the class. This is the default modifier for class members in TypeScript, so you don't need to specify it explicitly.
In this example, the `myPublicProperty` and `myPublicMethod` members are both `public`, so they can be accessed and modified from outside the class.
- private: A `private` member can only be accessed from within the class. It cannot be accessed from outside the class or its subclasses.
In this example, the `myPrivateProperty` and `myPrivateMethod` members are both `private`, so they cannot be accessed from outside the class.
- protected: A `protected` member can be accessed from within the class or its subclasses. It cannot be accessed from outside the class or its subclasses.
In this example, the `myProtectedProperty` and `myProtectedMethod` members are both `protected`, so they can be accessed from within the `MySubClass` subclass, but not from outside the class hierarchy.
Using the `public`, `private`, and `protected` modifiers can help you encapsulate and control access to class members in TypeScript, making your code more modular and maintainable.
class MyClass {
public myPublicProperty: string;
public myPublicMethod() {
// code here
}
}
const myInstance = new MyClass();
myInstance.myPublicProperty = "value";
myInstance.myPublicMethod();
class MyClass {
private myPrivateProperty: string;
private myPrivateMethod() {
// code here
}
}
const myInstance = new MyClass();
myInstance.myPrivateProperty = "value"; // ERROR: private property cannot be accessed from outside the class
myInstance.myPrivateMethod(); // ERROR: private method cannot be accessed from outside the class
class MyBaseClass {
protected myProtectedProperty: string;
protected myProtectedMethod() {
// code here
}
}
class MySubClass extends MyBaseClass {
myMethod() {
this.myProtectedProperty = "value"; // OK: can access protected property from subclass
this.myProtectedMethod(); // OK: can access protected method from subclass
}
}
const myInstance = new MySubClass();
myInstance.myProtectedProperty = "value"; // ERROR: protected property cannot be accessed from outside the class hierarchy
myInstance.myProtectedMethod(); // ERROR: protected method cannot be accessed from outside the class hierarchy
10.
What is a type assertion in TypeScript, and how can you use it?
In TypeScript, a type assertion is a way to tell the compiler the type of a value, even if the compiler cannot infer it automatically. This can be useful in situations where you know the type of a value, but the compiler does not, such as when working with external libraries or APIs that return values of unknown types.
Type assertions are expressed using the `as` keyword, followed by the desired type. There are two forms of type assertions in TypeScript: "angle-bracket" syntax and "as" syntax.
- Angle-bracket syntax:
In this example, we use angle-bracket syntax to tell the compiler that `myValue` is a string, so we can access its `length` property. The `myLength` variable is assigned the length of the string.
- "as" syntax:
In this example, we use "as" syntax to tell the compiler that `myValue` is a string, so we can access its `length` property. The `myLength` variable is assigned the length of the string.
Both forms of type assertions work in a similar way, but the "as" syntax is preferred in TypeScript, as it is more consistent with other language constructs and is easier to read.
Type assertions should be used with caution, as they can override the compiler's type checks and lead to runtime errors if used incorrectly. It is generally better to use type annotations and let the compiler infer types wherever possible, to ensure type safety and maintainability of the codebase. However, type assertions can be a useful tool in some situations, such as when working with third-party libraries or legacy code.
let myValue: any = "Hello, TypeScript!";
let myLength: number = (myValue).length;
let myValue: any = "Hello, TypeScript!";
let myLength: number = (myValue as string).length;