βββ README.md
/README.md:
--------------------------------------------------------------------------------
1 | # Top 100 Typescript Interview Questions in 2025
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | #### You can also find all 100 answers here π [Devinterview.io - Typescript](https://devinterview.io/questions/web-and-mobile-development/typescript-interview-questions)
11 |
12 |
13 |
14 | ## 1. What is _TypeScript_ and how does it differ from _JavaScript_?
15 |
16 | **TypeScript** is a statically-typed superset of **JavaScript**, developed and maintained by Microsoft. It enables enhanced code maintainability and predictability. After compiling, TypeScript code is transpiled into standard, browser-compatible JavaScript.
17 |
18 | Key distinctions between TypeScript and JavaScript include the use of type annotations, the ability to work with existing JavaScript code, and more.
19 |
20 | ### TypeScript Features & Benefits
21 |
22 | - **Type System**: Offers static typing, allowing developers to define the type of variables, parameters, and return values. This helps catch errors during development, reducing runtime issues.
23 |
24 | - **Advanced Language Features**: Incorporates modern ECMAScript syntax and features, often before they are rolled out in JavaScript. Additionally, TypeScript brings functional programming patterns, classes, and access modifiers (such as `public` and `private`)
25 |
26 | - **Compatibility with JavaScript**: TypeScript can interpret existing JavaScript code with minor or no modifications.
27 |
28 | - **Tooling and Extra Safety**: Provides enhanced autocompletion, refactoring, and documentation via TypeScript-aware tools. TypeScript helps catch and rectify common programming errors without needing to run the code.
29 |
30 | - **ECMAScript Compatibility**: TypeScript allows developers to target different **ECMAScript versions**, ensuring the generated JavaScript is compatible with the targeted browsers.
31 |
32 | - **Code Structure & Readability**: Promotes maintainability by enforcing a defined coding structure and fostering code clarity.
33 |
34 | ### TypeScript's Role in Modern Development
35 |
36 | - **Workplace Adaptability**: TypeScript is used in an extensive range of projects, from small utilities to large-scale applications.
37 |
38 | - **Community Support**: Supported by a vibrant developer community, TypeScript benefits from frequent updates, bug fixes, and useful extensions.
39 |
40 | - **On-Going Development**: A robust language server furnishes accurate tooling feedback, such as linting and error suggestions in real time.
41 |
42 | - **Rapid Enhancement**: The TypeScript team consistently introduces new features and reinforces existing ones.
43 |
44 |
45 | ## 2. Can you explain what is meant by "_TypeScript_ is a _superset_ of _JavaScript_"?
46 |
47 | **TypeScript** is often described as a **"superset of JavaScript"** because every valid JavaScript code is also a valid TypeScript code.
48 |
49 | TypeScript is designed in a way that it fully embraces existing **JavaScript syntax** and functionality. This ensures a smooth transition for developers wishing to adopt or migrate to TypeScript.
50 |
51 | ### Key TypeScript Features On Top of JavaScript
52 |
53 | - **Type Definitions**: TypeScript introduces static typing through type annotations. These are optional, enabling gradual adoption for existing codebases that might not need them.
54 |
55 | - **Newer JavaScript Features**: TypeScript extends JavaScript syntax, providing support for the latest ECMAScript standards more effectively through its compiler, even when the underlying JavaScript engine might not support them yet.
56 |
57 | - **Tooling and Error Detection**: TypeScript offers robust type-checking, increased code readability, and stronger compile-time error detection.
58 |
59 | ### Code Demonstration
60 |
61 | Here is the TypeScript code:
62 |
63 | ```typescript
64 | let num: number = 5;
65 | num = "this will raise a type error";
66 | ```
67 |
68 |
69 | ## 3. What are the _basic types_ available in _TypeScript_?
70 |
71 | **TypeScript** provides an assortment of basic types for different kinds of data, such as numbers, strings, boolean values, arrays, tuples and more.
72 |
73 | ### Common Basic Types in TypeScript
74 |
75 | - **Boolean**: Represents true/false values.
76 |
77 | - **Number**: Applies to both integer and floating-point numbers.
78 |
79 | - **String**: Refers to textual data.
80 |
81 | - **Array**: Offers a flexible way to work with structured data.
82 |
83 | - **Tuple**: Enables the definition of arrays with a fixed number of elements, each potentially of a different data type.
84 |
85 | - **Enum**: Provides a set of named constants such as days or colors.
86 |
87 | - **Any**: Offers a dynamic type, which can be used to bypass type-checking. It's typically best to be avoided, as it defeats the purpose of using TypeScript, which is primarily focused on static typing. However, there are certain use cases where it becomes necessary.
88 |
89 | - **Void**: Typically used as the return type for functions that don't return a value.
90 |
91 | - **Null** and **Undefined**: Allow for the assignment of null and undefined values, respectively. However, this isnβt enabled by default, and these are probably better handled using the `strict` mode settings in TypeScript.
92 |
93 | - **Never**: Represents the type of values that never occur. For instance, the return type of a function that doesn't reach its end or always throws an error.
94 |
95 | - **Object**: Any JavaScript object.
96 |
97 | - **Function**: Denotes a function type.
98 |
99 | ### Code Example: Basic TypeScript Types
100 |
101 | Here is the TypeScript code:
102 |
103 | ```typescript
104 | // Boolean
105 | let isActive: boolean = true;
106 |
107 | // Number
108 | let age: number = 30;
109 |
110 | // String
111 | let title: string = "Manager";
112 |
113 | // Array
114 | let scores: number[] = [85, 90, 78];
115 | // or use a compact form: let scores: Array
= [85, 90, 78];
116 |
117 | // Tuple
118 | let employee: [string, number, boolean] = ['John', 35, true];
119 |
120 | // Enum
121 | enum WeekDays { Monday, Tuesday, Wednesday, Thursday, Friday }
122 | let today: WeekDays = WeekDays.Wednesday;
123 |
124 | // Any
125 | let dynamicData: any = 20;
126 |
127 | // Void
128 | function greet(): void {
129 | console.log("Hello!");
130 | }
131 |
132 | // Null and Undefined
133 | let data: null = null;
134 | let user: undefined = undefined;
135 |
136 | // Never
137 | function errorMessage(message: string): never {
138 | throw new Error(message);
139 | }
140 |
141 | // Object
142 | let person: object = {
143 | name: 'John',
144 | age: 30
145 | };
146 |
147 | // Function
148 | let calculate: Function;
149 | calculate = function (x: number, y: number): number {
150 | return x + y;
151 | };
152 | ```
153 |
154 |
155 | ## 4. How do you declare _variables_ in _TypeScript_?
156 |
157 | In TypeScript, **variable** **declarations** support different methodologies for declaring variables and their associated types.
158 |
159 | ### Variable and Type Declaration Methods
160 |
161 | #### 1. var
162 |
163 | ```typescript
164 | var score: number = 100;
165 | ```
166 |
167 | This declaration can lead to **variable hoisting** and has global scope or function-level scope.
168 |
169 | #### 2. let
170 |
171 | Use `let` when you want to define variables within a **block scope**. This is the recommended default choice:
172 |
173 | ```typescript
174 | let playerName: string = "John";
175 | ```
176 |
177 | #### 3. const
178 |
179 | `const` allows you to declare **constants** and is especially useful for maintaining data integrity:
180 |
181 | ```typescript
182 | const apiKey: string = "your-api-key-here";
183 | ```
184 |
185 | #### 4. Function Scope
186 |
187 | All three methods (`var`, `let`, and `const`) are confined to their immediate function scope:
188 |
189 | ```typescript
190 | function doSomething() {
191 | let tempValue: number = 42;
192 | var result: boolean = true;
193 | }
194 | ```
195 |
196 | ### Rules for Variable Declaration and Initialization
197 |
198 | - **Order Matters**: In TypeScript, a variable must be declared before being used. This is not a requirement in JavaScript, but good JavaScript practice is to declare a variable before using it.
199 |
200 | If you're dealing with complex or interconnected codes, it's a good practice to use the `let` and `const` declarations that ensure the block-level scoping, thus helping with potential hoisting issues.
201 |
202 | - **Static Types**: TypeScript requires that you declare the data type of a variable (or let the system infer it) and then initialize it with a value of exactly the same type:
203 |
204 | ```typescript
205 | let count: number; // Declaration
206 | count = 42; // Allowed
207 | count = "42"; // Error! Type 'string' is not assignable to type 'number'.
208 | ```
209 |
210 | - **Type Inference**: TypeScript can often infer the variable's type based on its initialization value. This reduces the need to specify a type explicitly.
211 |
212 | ```typescript
213 | let word = "hello!"; // TypeScript infers the type as 'string' because of the initialization.
214 | ```
215 |
216 | ### Best Practices for Variable Declarations
217 |
218 | - **Use `const` Where You Can**: This approach isn't always possible, especially when dealing with object properties. However, favor `const` for better code readability and to prevent accidental data mutations.
219 |
220 | - **Prefer `let` over `var`**: `let` adheres better to **block-level scoping** and offers more predictability in the code.
221 |
222 | - **Initialize at Declaration**: Although TypeScript allows initializations after declarations, it's best to declare and initialize variables simultaneously to improve code clarity and type safety.
223 |
224 | - **Prefer Type Annotations**: Explicitly specifying variable types can improve code readability. However, when the variable type is obvious from the initialization, type inference should suffice.
225 |
226 |
227 | ## 5. What are _Interfaces_ in _TypeScript_ and how do they work?
228 |
229 | In TypeScript, an **interface** defines the structure and types of its members. It acts as a contract for the required properties and methods, ensuring that implementing classes or objects match this structure.
230 |
231 | ### Key Features of Interfaces
232 |
233 | - **Type Consistency**: Objects that adhere to an interface's structure are considered compatible with it.
234 | - **Optional and Readonly Members**: Interfaces allow for optional attributes and readonly members with the `?` and `readonly` keywords respectively.
235 | - **Call Signatures**: Interfaces can define method types, specifying function parameter and return types.
236 | - **Index Signatures**: Useful for specifying that an object can have any number of properties, all of a certain type.
237 |
238 | ### Core Use-Cases
239 |
240 | - **Standardizing Objects**: Ensuring that disparate objects share a common structure for increased cohesiveness and ease of use.
241 | - **Contract Enforcement**: Enforcing property and method requirements on classes to reduce errors and improve maintainability.
242 |
243 | ### Code Example: Basic Interface
244 |
245 | Here is the TypeScript code:
246 |
247 | ```typescript
248 | interface Point {
249 | x: number;
250 | y: number;
251 | }
252 |
253 | function printPoint(p: Point) {
254 | console.log(`Point coordinates: (${p.x}, ${p.y})`);
255 | }
256 |
257 | let pointA = { x: 3, y: 7 }; // This object matches Point's structure
258 | let pointB = { x: 8 }; // This object is missing the 'y' property
259 |
260 | printPoint(pointA); // Output: Point coordinates: (3, 7)
261 | printPoint(pointB); // Compile-time error due to incorrect structure
262 | ```
263 |
264 |
265 | ## 6. Describe the _Enum_ type and when you might use it.
266 |
267 | The **Enum** is a data type that simplifies the representation and management of discrete, named values. It's a foundational tool to ensure **type safety** in TypeScript and a number of vital use-cases:
268 |
269 | - **Reducing 'Magic Values'**: When ensuring readability and preventing repetitive literal values, such as `1`, `2`, or `'red'`.
270 | - **Configuring Behaviour**: influencing functionalities sets of associated values, such as HTTP methods, ordering or customer types.
271 | - **Ensuring Type Safety and Efficiency**: The predefined set of valid members and a clear data type ensures that value assignments and operations are unequivocal and consistent.
272 |
273 | ### Core Components
274 |
275 | - **Key**: a unique identifier, typically a number or string.
276 | - **Value**: Data associated with the key. If not provided, the key is used as the value.
277 |
278 | ### Standard, String, and Heterogeneous Enums
279 |
280 | - **Standard Enum**: Every key and value are of the same data type, typically numbers.
281 | - **String Enum**: All keys and values must be strings, ensuring consistent data representation.
282 | - **Heterogeneous Enum**: Defines keys with both number or string values. However, due to the mixed-type nature of these enums, it's best to steer clear of them in most cases.
283 |
284 | ### Code Example: Standard Enum
285 |
286 | Here is the TypeScript code:
287 |
288 | ```typescript
289 | enum HttpMethods {
290 | GET,
291 | POST,
292 | PUT,
293 | DELETE
294 | }
295 |
296 | const requestType: HttpMethods = HttpMethods.GET;
297 |
298 | // β This is not allowed due to type safety
299 | // const requestType2: HttpMethods = 'GET';
300 | ```
301 |
302 | In the example, the key `GET` is implicitly assigned the value `0`.
303 |
304 | ### Code Example: String Enum
305 |
306 | Here is the TypeScript code:
307 |
308 | ```typescript
309 | enum MediaTypes {
310 | Image = 'image',
311 | Video = 'video',
312 | Audio = 'audio'
313 | }
314 |
315 | const selectedType: MediaTypes = MediaTypes.Image;
316 |
317 | // β This is not allowed due to type safety
318 | // const selectedType2: MediaTypes = MediaTypes.Video;
319 |
320 | // β
Accessing the value
321 | const associatedText: string = MediaTypes.Image;
322 |
323 | // β This is not allowed due to type safety
324 | // const invalidType: MediaTypes = 'image';
325 | ```
326 |
327 | the Enum helps ensure the proper data type and its values.
328 |
329 | ### Pragmatic Use of Enums
330 |
331 | While Enums are a powerful tool for maintaining type safety, simplify associating related sets of values.
332 |
333 | However, a consideration is that an Enum value can be inferred or forced to be of any key and underlying value type.
334 |
335 | ### Potential Downsides of Enums
336 |
337 | - **Compilation Impact**: When used in a broader context, or in data structures like arrays or maps, TypeScript generates additional code to convert Enum keys to their associated values.
338 | - **Memory Usage**: Every usage of an Enum requires memory allocation for its value.
339 |
340 | When a simple constant would suffice or if there's a need for a more dynamic relationship between keys and values, detailed types would be a better alternative.
341 |
342 |
343 | ## 7. How do you define and use a _function_ in _TypeScript_?
344 |
345 | When defining a **function** in TypeScript, you have the following fundamental components to consider:
346 |
347 | - **Function Signature**: Comprising the function's purpose, parameters, type, and return value.
348 | - **Function Body**: Containing the actual operation or series of steps the function will execute.
349 |
350 | ### Key Concepts
351 |
352 | #### 1) Function Declaration
353 |
354 | To declare a function, you specify its name, its parameter list, and its return type. If the function doesn't return a value, you set the return type to `void`.
355 |
356 | Here is a code example:
357 |
358 | ```typescript
359 | function greet(name: string): void {
360 | console.log(`Hello, ${name}!`);
361 | }
362 | ```
363 |
364 | #### 2) Function Expression
365 |
366 | You can also declare functions using expressions, which involve assigning functions to variables as values. This approach allows you to be more flexible, such as when you're using **callbacks**.
367 |
368 | Here is an example:
369 |
370 | ```typescript
371 | let greet: (name: string) => void;
372 | greet = function(name: string): void {
373 | console.log(`Hello, ${name}!`);
374 | };
375 | ```
376 |
377 | #### 3) Optional and Default Parameters
378 |
379 | TypeScript supports both **optional** and **default** function parameters, enhancing the flexibility of your functions.
380 |
381 | **Optional Parameters** are denoted by a `?` symbol after the parameter name.
382 |
383 | Here is the code example:
384 |
385 | ```typescript
386 | function greet(name: string, title?: string) {
387 | if (title) {
388 | console.log(`Hello, ${title} ${name}!`);
389 | } else {
390 | console.log(`Hello, ${name}!`);
391 | }
392 | }
393 | ```
394 |
395 | **Default Parameters** are when you assign a default value to a parameter:
396 |
397 | Here is the code example:
398 |
399 | ```typescript
400 | function greet(name = "Stranger") {
401 | console.log(`Hello, ${name}!`);
402 | }
403 | ```
404 |
405 | #### 4) Use Rest Parameters
406 |
407 | You can define a parameter as a "rest" parameter, which means the function can accept any number of arguments for that parameter.
408 |
409 | Here is the code example:
410 |
411 | ```typescript
412 | function introduce(greeting: string, ...names: string[]) {
413 | console.log(`${greeting}, ${names.join(", ")}!`);
414 | }
415 |
416 | introduce("Hello", "Alice", "Bob", "Carol");
417 | ```
418 |
419 | #### 5) Function Overloads
420 |
421 | You can declare multiple function **overloads** to define a set of parameters and their return types for a single function. This feature is especially beneficial when the function's behavior logically varies based on different input types.
422 |
423 | Here is the code example:
424 |
425 | ```typescript
426 | function specialGreet(name: string): void;
427 | function specialGreet(title: string, name: string): void;
428 |
429 | function specialGreet(a: any, b?: any): void {
430 | if (b) {
431 | console.log(`Hello, ${a}, ${b}`);
432 | } else {
433 | console.log(`Hello, ${a}`);
434 | }
435 | }
436 | ```
437 |
438 | #### 6) Call Signature
439 |
440 | When using objects in TypeScript, you have the **call signature** to define the expected function structure for a specific method within the object.
441 |
442 | Here is a code example:
443 |
444 | ```typescript
445 | type Greeter = {
446 | (name: string): void
447 | };
448 |
449 | let welcome: Greeter;
450 | welcome = function(name: string): void {
451 | console.log(`Welcome, ${name}!`);
452 | };
453 | ```
454 |
455 |
456 | ## 8. What does "_type inference_" mean in the context of _TypeScript_?
457 |
458 | In TypeScript, **type inference** is a core feature that allows the type of a variable to be automatically determined from its value. This provides the benefits of static typing without the need for explicit type annotations.
459 |
460 | ### How It Works
461 |
462 | TypeScript employs a **best common type** algorithm to infer a variable's type. When TypeScript encounters multiple types for a variable during assignment or an array literal, it computes the **union** of these types and selects the best common type for the variable.
463 |
464 | ### Code Example: Type Inference
465 |
466 | Consider the following code:
467 |
468 | ```typescript
469 | let value = 10; // Type 'number' inferred
470 | let message = "Hello, TypeScript!"; // Type 'string' inferred
471 |
472 | function add(a: number, b: number) {
473 | return a + b;
474 | }
475 |
476 | let sum = add(5, 7); // Type 'number' inferred
477 | ```
478 |
479 | TypeScript can infer the most likely type from the context, such as:
480 |
481 | - When a value is assigned immediately, TypeScript assigns the value's type to the variable.
482 | - Type information from adjacent types is used to determine the best common type. If all values are of a compatible type, that type is used.
483 |
484 | ### Benefits of Type Inference
485 |
486 | - **Conciseness**: Eliminates the need for explicit type declarations, leading to more compact and readable code.
487 | - **Adaptability**: Codebase types align naturally with values, enhancing maintainability when values change.
488 | - **Error Reduction**: Reduces the risk of inconsistencies between the declared type and the actual value.
489 |
490 |
491 | ## 9. Explain the use of '_let_' and '_const_' in _TypeScript_.
492 |
493 | **TypeScript** makes use of `const` and `let` for variable declaration. These two keywords offer explicitness, scoping, and immutability for efficient code maintenance.
494 |
495 | ### Core Distinctions
496 |
497 | - **const**: Designates constants that remain unchanged once declared. It's important to note that this makes the reference immutable but doesn't actively prevent alteration of the internal state for complex objects like arrays.
498 |
499 | - **let**: Initiates variables with standard mutable behavior.
500 |
501 | ### Code Example: `const`
502 |
503 | Here is the TypeScript code:
504 |
505 | ```typescript
506 | const productId: number = 5;
507 | let productName: string = 'Tesla';
508 |
509 | const getProductDetails = (id: number): string => {
510 | return `Product ID: ${id}`;
511 | };
512 |
513 | // Attempting to modify will result in a compilation error
514 | // productId = 6;
515 |
516 | // Reference is still immutable
517 | const anotherProductId: number = 10;
518 | // This will throw a compilation error since it's a constant
519 | // anotherProductId = 12;
520 |
521 | // Modifying internal state of an object is allowed for a const
522 | const myArray: number[] = [1, 2, 3];
523 | myArray.push(4);
524 | ```
525 |
526 | ### Code Example: `let`
527 |
528 | Here is the TypeScript code:
529 |
530 | ```typescript
531 | let vehicleType: string = 'Car';
532 |
533 | if (true) {
534 | let vehicleType: string = 'Motorcycle';
535 | console.log(vehicleType); // Output: Motorcycle
536 | }
537 |
538 | console.log(vehicleType); // Output: Car
539 | ```
540 |
541 |
542 | ## 10. How do you compile _TypeScript_ files into _JavaScript_?
543 |
544 | Compiling **TypeScript** (.ts) into **JavaScript** (.js) involves integrating a TypeScript compiler (`tsc`). You can customize the compilation process using `tsconfig.json` and even adopt more advanced methods to suit project needs:
545 |
546 | ### Workflow Steps
547 |
548 | 1. **File Creation**: Write TypeScript files (.ts).
549 |
550 | 2. **Compiler Config**: Set up a `tsconfig.json` file with compilation options.
551 |
552 | 3. **Compile**: Execute the `tsc` command to initiate the compilation process.
553 |
554 | 4. **Output Verification**: Review the generated JavaScript files.
555 |
556 |
557 | #### TypeScript Configuration (`tsconfig.json`)
558 |
559 | Here is the `tsconfig.json` file. The full configuration guide is available [here](https://www.typescriptlang.org/tsconfig).
560 |
561 | ```json
562 | {
563 | "compilerOptions": {
564 | "target": "ES5",
565 | "module": "commonjs",
566 | "strict": true,
567 | "outDir": "dist",
568 | "rootDir": "src"
569 | },
570 | "include": [
571 | "src/**/*.ts"
572 | ],
573 | "exclude": [
574 | "node_modules",
575 | "**/*.spec.ts"
576 | ]
577 | }
578 | ```
579 |
580 | ### Practical Example: Vineyard Residential Task Management App
581 |
582 | Here is a practical and comprehensive `tsconfig.json` file.
583 |
584 | ```json
585 | {
586 | "compilerOptions": {
587 | "target": "es5",
588 | "module": "commonjs",
589 | "lib": ["dom", "es2015", "es5", "es6", "es7", "es2015.collection"],
590 | "allowJs": true,
591 | "checkJs": false,
592 | "jsx": "react",
593 | "declaration": false,
594 | "sourceMap": true,
595 | "outDir": "dist",
596 | "rootDir": "src",
597 | "strict": true,
598 | "noImplicitAny": true,
599 | "noImplicitThis": true,
600 | "moduleResolution": "node",
601 | "esModuleInterop": true,
602 | "forceConsistentCasingInFileNames": true,
603 | "removeComments": true,
604 | "suppressImplicitAnyIndexErrors": true,
605 | "typeRoots": ["node_modules/@types", "custom-typings"],
606 | "baseUrl": ".",
607 | "paths": {
608 | "components/*": ["src/components/*"],
609 | "utils/*": ["src/utils/*"],
610 | },
611 | "experimentalDecorators": true,
612 | "emitDecoratorMetadata": true,
613 | "incremental": true,
614 | "diagnostics": true,
615 | "resolveJsonModule": true,
616 | "isolatedModules": true,
617 | "newLine": "LF",
618 | "watchOptions": {
619 | "watchFile": "useFsEvents",
620 | "fallbackPolling": "dynamicPriority",
621 | "polling": true,
622 | "esModuleInterop": true,
623 | "pollingInterval": 2500,
624 |
625 | "followSymlinks": true
626 | }
627 | },
628 | "include": [
629 | "src/**/*.ts",
630 | "src/**/*.tsx",
631 | "@types"
632 | ],
633 | "exclude": [
634 | "node_modules",
635 | "dist"
636 | ]
637 | }
638 | ```
639 |
640 | ### Advanced Configuration
641 |
642 | - **Project Reference**: Useful for code splitting in large projects.
643 | - **Custom Transformers**: Employ custom logic during the compilation process.
644 | - **Programmatic API**: Provides flexibility in managing compiler settings and execution.
645 |
646 |
647 | ## 11. Explain _classes_ in _TypeScript_. How are they different from _ES6 classes_?
648 |
649 | While TypeScript and **ES6** classes share many similarities, TypeScript's classes offer additional features and strong typing to make your code more robust.
650 |
651 | ### Key Shared Class Features
652 |
653 | - **Inheritance**: Subclasses (children) can extend parent classes, inheriting their methods and properties.
654 | - **Polymorphism**: Derived classes can define methods with the same name as their parent.
655 | - **Encapsulation**: Data hiding is supported through access modifiers, such as `public`, `private`, and `protected`.
656 | - **Constructor**: Instantiation starts with a constructor method, if defined.
657 |
658 | ### Unique TypeScript Class Features
659 |
660 | #### Field Declaration
661 |
662 | In TypeScript, you can specify fields directly in the class without initializing them. Automatic initialization to `undefined` occurs during object creation. ES6 requires initializing fields in the constructor or within their declaration.
663 |
664 | ```typescript
665 | class Example {
666 | // Field is automatically initialized to undefined upon object creation
667 | someField: string;
668 | }
669 | ```
670 |
671 | #### Abstract Classes
672 |
673 | TypeScript supports abstract classes to serve as a blueprint for other classes. They cannot be instantiated on their own but can provide some implementation that derived classes can override.
674 |
675 | ```typescript
676 | abstract class AbstractExample {
677 | abstract someMethod(): void; // Method has no implementation (abstract)
678 | }
679 | ```
680 |
681 | #### Readonly Properties
682 |
683 | You can mark class properties as `readonly`, ensuring they are only set upon declaration or within the class constructor.
684 |
685 | ```typescript
686 | class Example {
687 | readonly id: number;
688 | constructor(id: number) {
689 | this.id = id; // Readonly can only be assigned in the constructor or declaration
690 | }
691 | }
692 | ```
693 |
694 | #### Static Members
695 |
696 | Classes in TypeScript support static members, such as properties and methods that belong to the class itself, rather than to instances of the class.
697 |
698 | ```typescript
699 | class Example {
700 | static count = 0; // Static property
701 | static incrementCount() {
702 | Example.count++;
703 | }
704 | }
705 | ```
706 |
707 | #### Accessor Functions
708 |
709 | You can define `get` and `set` functions in TypeScript, known as accessor functions, to control how class properties are accessed and modified.
710 |
711 | ```typescript
712 | class Example {
713 | private _name: string;
714 |
715 | get name(): string {
716 | return this._name;
717 | }
718 |
719 | set name(newName: string) {
720 | this._name = newName.trim();
721 | }
722 | }
723 | ```
724 |
725 | #### Parameter Properties
726 |
727 | TypeScript provides a shortcut to declare a property and initialize it from the constructor parameter. This method can make code more concise, especially when a constructor parameter corresponds directly to a class property.
728 |
729 | ```typescript
730 | class Example {
731 | constructor(private _name: string, public age: number) {
732 | // Private _name property created and initialized from constructor parameter
733 | // Public age property created and initialized from constructor parameter
734 | }
735 | }
736 | ```
737 |
738 | #### Intersection Types for Classes
739 |
740 | In TypeScript, when you define a base class and then later extend it, you are creating an intersection type. This means the child class will inherit all the properties and methods from both its parent(s) and itself.
741 |
742 | ### ES6 Additional Features not Present in TypeScript
743 |
744 | #### Class Expressions
745 |
746 | Both ES6 and TypeScript support class expressions, which allows you to define a class without a class name.
747 |
748 | In ES6:
749 |
750 | ```javascript
751 | const Animal = class {
752 | // Class methods and properties defined here
753 | };
754 | ```
755 |
756 | #### Iterator Protocol
757 |
758 | ES6 classes support the Iterator protocol, making it easier to iterate over objects.
759 |
760 | ```typescript
761 | class IterableExample implements Iterable {
762 | // Implement iterator function for strings
763 | [Symbol.iterator]() {
764 | let index = 0;
765 | const data = ['one', 'two', 'three'];
766 | return {
767 | next: () => {
768 | if (index < data.length) {
769 | return { value: data[index++], done: false };
770 | }
771 | return { value: undefined, done: true };
772 | }
773 | };
774 | }
775 | }
776 | ```
777 |
778 |
779 | ## 12. How do you implement _Inheritance_ in _TypeScript_?
780 |
781 | Let's look at how you can use **inheritance** in TypeScript using both **ES6 classes** and **prototypal inheritance**.
782 |
783 | ### 1. Inheritance with ES6 Class Syntax
784 |
785 | With the advent of ES6, a more familiar class-based inheritance method was introduced. This method is usually easier to read and understand.
786 |
787 | #### Code Example: Inheritance using ES6 Classes
788 |
789 | Here is the TypeScript code:
790 |
791 | ```typescript
792 | class Animal {
793 | private name: string;
794 |
795 | constructor(theName: string) {
796 | this.name = theName;
797 | }
798 |
799 | move(distanceInMeters: number = 0) {
800 | console.log(`${this.name} moved ${distanceInMeters}m.`);
801 | }
802 | }
803 |
804 | class Snake extends Animal {
805 | constructor(name: string) {
806 | super(name);
807 | }
808 |
809 | move(distanceInMeters = 5) {
810 | console.log("Slithering...");
811 | super.move(distanceInMeters);
812 | }
813 | }
814 |
815 | const mySnake = new Snake("Cobra");
816 | mySnake.move(); // Output: Slithering... Cobra moved 5m.
817 | ```
818 |
819 | ### 2. Inheritance with Prototypal Methodology
820 |
821 | Prior to ES6, TypeScript, like JavaScript, used a **prototypal** inheritance approach.
822 |
823 | The prototypal mechanism can be useful when developing complex object structures, but it is important to be aware of the nuances in order to avoid unexpected behavior.
824 |
825 | #### Code Example: Prototypal Inheritance in TypeScript
826 |
827 | Here is the TypeScript code:
828 |
829 | ```typescript
830 | // Define the Parent Class
831 | function Animal(this: Animal, name: string) {
832 | this.name = name;
833 | }
834 |
835 | Animal.prototype.move = function(distanceInMeters: number = 0) {
836 | console.log(`${this.name} moved ${distanceInMeters}m.`);
837 | };
838 |
839 | // Define the Child Class
840 | function Snake(name: string) {
841 | Animal.call(this, name);
842 | }
843 |
844 | // Set up the Inheritance
845 | Snake.prototype = Object.create(Animal.prototype);
846 | Snake.prototype.constructor = Snake;
847 |
848 | // Override the Base Type's Method
849 | Snake.prototype.move = function(distanceInMeters = 5) {
850 | console.log("Slithering...");
851 | Animal.prototype.move.call(this, distanceInMeters);
852 | };
853 |
854 | const mySnake = new Snake("Cobra");
855 | mySnake.move(); // Output: Slithering... Cobra moved 5m.
856 | ```
857 |
858 | #### Simplified Methods
859 |
860 | Using the prototypal construct can be perplexing at first, but its strength lies in its flexibility.
861 |
862 | You can avoid the complexities of direct prototype assignments using ES5 derived constructions, as seen next:
863 |
864 | ```typescript
865 | function Animal(name: string) {
866 | this.name = name;
867 | }
868 |
869 | Animal.prototype.move = function(distanceInMeters: number = 0) {
870 | console.log(`${this.name} moved ${distanceInMeters}m.`);
871 | };
872 |
873 | function Snake(name: string) {
874 | Animal.call(this, name);
875 | }
876 |
877 | // Utilize `Object.create` for simplified prototype delegation
878 | Snake.prototype = Object.create(Animal.prototype);
879 | Snake.prototype.constructor = Snake;
880 |
881 | Snake.prototype.move = function(distanceInMeters = 5) {
882 | console.log("Slithering...");
883 | Animal.prototype.move.call(this, distanceInMeters);
884 | };
885 | ```
886 |
887 |
888 | ## 13. What are _access modifiers_ and how do they work in _TypeScript_?
889 |
890 | **Access modifiers** are TypeScript's way of controlling class member visibility and mutability. They enforce encapsulation and are especially useful for object-oriented design.
891 |
892 | ### Key Modifiers
893 |
894 | - **Public**: Default for class members. They are accessible from both inside and outside the class.
895 |
896 | - **Protected**: Members can be accessed within the class and its subclasses. They help establish the "is-a" relationship.
897 |
898 | - **Private**: Marks members as accessible only within the declaring class. This ensures they're not modified or accessed externally.
899 |
900 | #### Code Example: Access Modifiers in Action
901 |
902 | Here is the TypeScript code:
903 |
904 | ```typescript
905 | class Person {
906 | public name: string;
907 | private age: number;
908 | protected contact: string;
909 |
910 | constructor(name: string, age: number, contact: string) {
911 | this.name = name;
912 | this.age = age;
913 | this.contact = contact;
914 | }
915 | }
916 |
917 | class Employee extends Person {
918 | private employeeId: string;
919 |
920 | constructor(name: string, age: number, contact: string, employeeId: string) {
921 | super(name, age, contact);
922 | this.employeeId = employeeId;
923 | }
924 |
925 | public displayDetails(): void {
926 | console.log(`${this.name} - ${this.age} - ${this.contact} - ${this.employeeId}`);
927 | }
928 | }
929 |
930 | // Somewhere in your code
931 | const person = new Person("John Doe", 30, "1234567");
932 | console.log(person.name); // Accessible
933 | console.log(person.age); // ERROR: 'age' is private
934 |
935 | const employee = new Employee("Jane Doe", 25, "2345678", "E123");
936 | console.log(employee.contact); // ERROR: 'contact' is protected
937 | employee.displayDetails(); // Correctly displays details
938 |
939 | employee.age = 35; // ERROR: 'age' is private
940 | employee.contact = "3456789"; // ERROR: 'contact' is protected
941 | ```
942 |
943 |
944 | ## 14. Discuss _Abstract classes_ and their purposes in _TypeScript_.
945 |
946 | In TypeScript, **abstract classes serve as blueprints** that guide derived classes, essentially laying out the structure without necessarily providing complete implementations of methods.
947 |
948 | ### Core Features of Abstract Classes
949 |
950 | #### Method Signatures
951 |
952 | **Abstract classes define method signatures** without specifying their functionality. This feature provides a comprehensive form for derived classes to work from.
953 |
954 | #### Specific Method Definitions
955 |
956 | In addition to method signatures, abstract classes can contain completely implemented methods. These methods either support the abstract methods or serve as independent functionalities.
957 |
958 | #### Abstract and Non-Abstract Members Separation
959 |
960 | Abstract classes clearly demarcate between methods that require implementation by derived classes and those that are either fully implemented or optional.
961 |
962 | ### Common Use-Cases for Abstract Classes
963 |
964 | - Facilitate Reusability: Abstract classes help in consolidating common or shared functionalities among several derived classes.
965 |
966 | - Contract Enforcement: They ensure that derived classes conform to a shared structure, guaranteeing a defined set of methods that must be implemented.
967 |
968 | - Partial Implementations: Abstract classes allow for a mix of fully implemented methods alongside those requiring concrete implementations in derived classes.
969 |
970 | ### TypeScript Utility: Static Properties
971 |
972 | Abstract classes in TypeScript can have **static members**, which belong to the class itself and not to any specific instance. This feature provides a convenient way to define properties or methods that are accessible without the need for class instantiation.
973 |
974 | ### Code Example: Abstract Class
975 |
976 | Here is the TypeScript code:
977 |
978 | ```typescript
979 | abstract class Shape {
980 | abstract getArea(): number;
981 | abstract getPerimeter(): number;
982 | color: string;
983 |
984 | constructor(color: string) {
985 | this.color = color;
986 | }
987 |
988 | static defaultColor: string = 'red';
989 |
990 | describe() {
991 | return `This shape is ${this.color}.`;
992 | }
993 | }
994 |
995 | // This will throw an error because the derived class does not provide concrete implementations for abstract methods.
996 | class Circle extends Shape {
997 | constructor(public radius: number, color: string) {
998 | super(color);
999 | }
1000 |
1001 | // The 'Circle' class inherited the following properties from 'Shape', but neither implements nor specifies them in the derived class: 'getArea' and 'getPerimeter'.
1002 | getArea(): number {
1003 | return Math.PI * this.radius ** 2;
1004 | }
1005 |
1006 | getPerimeter(): number {
1007 | return 2 * Math.PI * this.radius;
1008 | }
1009 | }
1010 |
1011 | const myCircle = new Circle(5, 'blue');
1012 | console.log(myCircle.getArea()); // Outputs: 78.54
1013 | console.log(myCircle.describe()); // Outputs: This shape is blue.
1014 | console.log(Shape.defaultColor); // Outputs: red
1015 | ```
1016 |
1017 |
1018 | ## 15. Can you describe the use of _Constructors_ within _TypeScript classes_?
1019 |
1020 | **TypeScript** provides a convenient way to define **constructors** for classes using the `constructor` keyword. A constructor method allows you to initialize class members and can have access specifiers. They are useful for setting up an object's initial state.
1021 |
1022 | ### Key Features
1023 |
1024 | - **Automatic Invocation**: The constructor is automatically called when an object of the class is instantiated.
1025 | - **Single Unique Constructor**: A class can only have one constructor, providing a centralized place for initialization.
1026 | - **Overload Capabilities**: You can overload a constructor to define multiple ways of object initialization.
1027 |
1028 | ### Example: Constructor in TypeScript
1029 |
1030 | We use the `this` keyword to refer to the current instance, ensuring proper data assignment.
1031 |
1032 | ```typescript
1033 | class Person {
1034 | // Member variables
1035 | name: string;
1036 | age: number;
1037 |
1038 | // Constructor
1039 | constructor(name: string, age: number) {
1040 | this.name = name;
1041 | this.age = age;
1042 | }
1043 | }
1044 | ```
1045 |
1046 | ### Constructor Access Modifiers
1047 |
1048 | TypeScript supports **access modifiers** on constructor parameters, enabling concise and safe class initialization.
1049 |
1050 | - **Public**: Parameters without a modifier are public by default.
1051 | - **Private**: Adding the `private` keyword makes them accessible within the class only.
1052 | - **Read-Only**: Combining `readonly` with parameter and the private or public access modifier ensures the parameter is assigned a value just once, in the constructor.
1053 |
1054 |
1055 |
1056 |
1057 | #### Explore all 100 answers here π [Devinterview.io - Typescript](https://devinterview.io/questions/web-and-mobile-development/typescript-interview-questions)
1058 |
1059 |
1060 |
1061 |
1062 |
1063 |
1064 |
1065 |
1066 |
--------------------------------------------------------------------------------