Typescript
Typescript
The built-in data types are also known as primitive data types in TypeScript.
The three primitive types of TypeScript are string, number and boolean.
These three types are similar to their JavaScript counterparts.
o Number type is used to represent numeric values. All the numbers in
TypeScript are stored as floating point values.
Syntax: let identifier: number = value;
o String type is used to represent text values. We include literals in our
scripts by enclosing them in single or double quotation marks.
Syntax: let identifier: string = “”;
o Boolean type is used to represent a logical value that can have either a
‘true’ or ‘false’ value.
Syntax: let identifier: bool = Boolean value;
One of the most apparent differences between these two languages is that
JavaScript is a scripting language while TypeScript is an object-oriented
language.
TypeScript also has the static typing feature, and it offers support for
parameter functions and models.
JavaScript doesn’t feature any of these capabilities.
o Object-Oriented Language
o Support JavaScript Libraries
o JavaScript is TypeScript
o TypeScript is Portable
o DOM Manipulation
o TypeScript is just JavaScript
13. List some benefits of using TypeScript.
38. How to generate TypeScript definition file from any .ts file?
We can generate TypeScript definition file from any .ts file by using tsc
compiler. It will
be generating a TypeScript definition which makes our TypeScript file
reusable.
tsc --declaration file1.ts
42. How to check null and undefined in TypeScript?
Yes, we can use TypeScript on the backend. We can understand it with the
following
example. Here, we choose Node.js and have some additional type safety and
the other
abstraction that the language brings.
Install Typescript
o
compiler
npm i -g typescript
o The TypeScript compiler takes options in the tsconfig.json file. This file
determines where to put built files.
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "build"
}
}
Compile ts
o
files
tsc
Run
o
node
build/index.js
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
- Interface: An interface declaration always introduces a named object type.
type: A type alias declaration can introduce a name for any kind of type,
including
primitive, union, and intersection types.
- Interface: An interface can be named in an extends or implements clause.
type: Type alias for an object type literal cannot be named in an extends or
implements
clause.
- Interface: Interfaces create a new name that is used everywhere.
type: Type alias don’t create a new name.
- Interface: An interface can have multiple merged declarations.
type: Type alias for an object type literal cannot have multiple merged
declarations.
45. What are Ambients in TypeScripts and when to use them?
Ambient declarations tell the compiler about the actual source code exist
elsewhere. If
these source codes do not exist at runtime and we try to use them, then it
will break
without warning.
Ambient declarations files are like docs file. If the source changes, the docs
need to be
kept updated also. If the ambient declaration file is not updated, then we will
get
compiler errors.
The Ambient declarations allow us to safely and easily use existing popular
JavaScript
libraries like jquery, angularjs, nodejs, etc.
o TypeScript Map file is a source map file which holds information about our
original files.
o .map files are source map files that let tools map between the emitted
JavaScript
code and the TypeScript source files that created it.
o Many debuggers can consume these files so we can debug the TypeScript
file
instead of the JavaScript file.
- Non-Relative
A non-relative import can be resolved relative to baseUrl, or through path
mapping. In
other words, we use non-relative paths when importing any of our external
dependencies.
Example:
import * as $ from "jquery";
import { Component } from "@angular/core";
- Relative
Relative imports can be used for our own modules that are guaranteed to
maintain their
relative location at runtime. A relative import is starts with /, ./ or ../.
Example:
import Entry from "./components/Entry";
import {DefaultHeaders} from "../constants/http";
52. What is an anonymous function?
If subclass (child class) has the same method as declared in the parent class,
it is known
as method overriding. In other words, redefined the base class methods in
the derived
class or child class.
Rules for Method Overriding
o The method must have the same name as in the parent class
o The method must have the same parameter as in the parent class.
o There must be an IS-A relationship (inheritance).
Example
class NewPrinter extends Printer {
doPrint(): any {
super.doPrint();
console.log("Called Child class.");
}
doInkJetPrint(): any {
console.log("Called doInkJetPrint().");
}
}
let printer: new () => NewPrinter;
printer.doPrint();
printer.doInkJetPrint();
We use arrays to store values of the same type. Arrays are ordered and
indexed
collections of values. The indexing starts at 0, i.e., the first element has
index 0, the
second has index 1, and so on.
Here is the syntax to declare and initialize an array in TypeScript.
let values: number[] = [];
values[0] = 10;
values[1] = 20;
values[2] = 30;
You can also create an array using the short-hand syntax as follows:
let values: number[] = [15, 20, 25, 30];
TypeScript provides an alternate syntax to specify the Array type.
let values: Array<number> = [15, 20, 25, 30];
There are times when you want to store a value in a variable but don’t know
the type
of that variable in advance. For example, the value is coming from an API call
or the
user input. The ‘any’ type allows you to assign a value of any type to the
variable of
type any.
let person: any = "Foo";
Here is an example that demonstrates the usage of any type.
// json may come from a third-party API
const employeeData: string = `{"name": "John Doe", "salary": 60000}`;
// parse JSON to build employee object
const employee: any = JSON.parse(employeeData);
console.log(employee.name);
console.log(employee.salary);
TypeScript assumes a variable is of type any when you don’t explicitly
provide the type,
and the compiler cannot infer the type from the surrounding context.
The void indicates the absence of type on a variable. It acts as the opposite
type to
any. It is especially useful in functions that don’t return a value.
function notify(): void {
alert("The user has been notified.");
}
If a variable is of type void, you can only assign the null or undefined values
to that
variable.
The unknown type is the type-safe counterpart of any type. You can assign
anything to
the unknown, but the unknown isn’t assignable to anything but itself and
any, without
performing a type assertion of a control-flow-based narrowing. You cannot
perform
any operations on a variable of an unknown type without first asserting or
narrowing it
to a more specific type.
Consider the following example. We create the foo variable of unknown type
and
assign a string value to it. If we try to assign that unknown variable to a
string variable
bar, the compiler gives an error.
let foo: unknown = "Akshay";
let bar: string = foo; // Type 'unknown' is not assignable to type
'string'.(2322)
You can narrow down a variable of an unknown type to something specific by
doing
typeof checks or comparison checks or using type guards. For example, we
can get rid
of the above error by
let foo: unknown = "Akshay";
let bar: string = foo as string;
var: Declares a function-scoped or global variable. You can optionally set its
value
during the declaration. Its behavior and scoping rules are similar to the var
keyword in
JavaScript. For example,
var foo = "bar";
let: Declares a block-scoped local variable. Similar to var, you can optionally
set the
value of a variable during the declaration. For example,
let a = 5;
if (true) {
let a = 10;
console.log(a); // 10
}
console.log(a); // 5
const: Declares a block-scoped constant value that cannot be changed after
it’s
initialized. For example,
const a = 5;
if (true) {
a = 10; // Error: Cannot assign to 'a' because it is a constant.(2588)
}
Objects are dictionary-like collections of keys and values. The keys have to
be unique.
They are similar to arrays and are also sometimes called associative arrays.
However,
an array uses numbers to index the values, whereas an object allows you to
use any
other type as the key.
In TypeScript, an Object type refers to any value with properties. It can be
defined by
simply listing the properties and their types. For example,
let pt: { x: number; y: number } = {
x: 10,
y: 20
};
An object type can have zero or more optional properties by adding a ‘?’
after the
property name.
let pt: { x: number; y: number; z?: number } = {
x: 10,
y: 20
};
console.log(pt);
In the example above, because the property ‘z’ is marked as optional, the
compiler
won’t complain if we don’t provide it during the initialization.
As the name suggests, the never type represents the type of values that
never occur.
For example, a function that never returns a value or that always throws an
exception
can mark its return type as never.
function error(message: string): never {
throw new Error(message);
}
You might wonder why we need a ‘never’ type when we already have ‘void’.
Though
both types look similar, they represent two very different concepts.
A function that doesn't return a value implicitly returns the value undefined
in
JavaScript. Hence, even though we are saying it’s not returning anything, it’s
returning
‘undefined’. We usually ignore the return value in these cases. Such a
function is
inferred to have a void return type in TypeScript.
// This function returns undefined
function greet(name: string) {
console.log(`Hello, ${name}`);
}
let greeting = greet("David");
console.log(greeting); // undefined
In contrast, a function that has a never return type never returns. It doesn't
return
undefined, either. There are 2 cases where functions should return never
type:
1. In an unending loop e.g a while(true){} type loop.
2. A function that throws an error e.g function foo(){throw new
Exception('Error
message')}
TypeScript fully supports classes. The TypeScript syntax for class declaration
is similar
to that of JavaScript, with the added type support for the member
declarations.
Here is a simple class that defines an Employee type.
class Employee {
name: string;
salary: number;
constructor(name: string, salary: number) {
this.name = name;
this.salary = salary;
}
promote() : void {
this.salary += 10000;
}
}
You can create an instance (or object) of a class by using the new keyword.
// Create a new employee
let john = new Employee("John", 60000);
console.log(john.salary); // 60000
john.promote();
console.log(john.salary); // 70000
Optional chaining allows you to access properties and call methods on them
in a
chain-like fashion. You can do this using the ‘?.’ operator.
TypeScript immediately stops running some expression if it runs into a ‘null’
or
‘undefined’ value and returns ‘undefined’ for the entire expression chain.
Using optional chaining, the following expression
let x = foo === null || foo === undefined ? undefined : foo.bar.baz();
can be expressed as:
let x = foo?.bar.baz();
76. What is meant by type inference?
TTypeScript can infer the type of a variable when you don’t provide an
explicit type.
This is known as type inference. This is usually done when the variables or
parameters
are initialized during the declaration.
For example, TypeScript knows that the variable foo is a string, even though
we don’t
mention string as a type.
let foo = "this is a string";
console.log(typeof foo); // "string"
When the TypeScript compiler uses the location (or context) of a variable to
infer its
type, it’s called contextual typing.
In the following example, TypeScript uses the Window.onmousedown
function type
information to infer the type of the function expression on the right-hand
side of the
assignment. This allows it to infer the type of the e parameter, which does
have a
button property but not a property named foo.
window.onmousedown = function (e) {
console.log(e.button); //<- OK
console.log(e.foo); //<- Error!
};
82. What are abstract classes? When should you use one?
TAbstract classes are similar to interfaces in that they specify a contract for
the objects,
and you cannot instantiate them directly. However, unlike interfaces, an
abstract class
may provide implementation details for one or more of its members.
An abstract class marks one or more of its members as abstract. Any classes
that
extend an abstract class have to provide an implementation for the abstract
members
of the superclass.
Here is an example of an abstract class Writer with two member functions.
The write()
method is marked as abstract, whereas the greet() method has an
implementation.
Both the FictionWriter and RomanceWriter classes that extend from Writer
have to
provide their specific implementation for the write method.
abstract class Writer {
abstract write(): void;
greet(): void {
console.log("Hello, there. I am a writer.");
} }
class FictionWriter extends Writer {
write(): void {
console.log("Writing a fiction.");
} }
class RomanceWriter extends Writer {
write(): void {
console.log("Writing a romance novel.");
} }
const john = new FictionWriter();
john.greet(); // "Hello, there. I am a writer."
john.write(); // "Writing a fiction."
const mary = new RomanceWriter();
mary.greet(); // "Hello, there. I am a writer."
mary.write(); // "Writing a romance novel."
Intersection types let you combine the members of two or more types by
using the ‘&’
operator. This allows you to combine existing types to get a single type with
all the
features you need.
The following example creates a new type Supervisor that has the members
of types
Employee and Manager.
interface Employee {
work: () => string;
}
interface Manager {
manage: () => string;
}
type Supervisor = Employee & Manager;
// john can both work and manage
let john: Supervisor;
Type aliases give a new, meaningful name for a type. They don’t create new
types but
create new names that refer to that type.
For example, you can alias a union type to avoid typing all the types
everywhere that
value is being used.
type alphanumeric = string | number;
let value: alphanumeric = "";
value = 10;
Tuples are a special type in TypeScript. They are similar to arrays with a
fixed number
of elements with a known type. However, the types need not be the same.
// Declare a tuple type and initialize it
let values: [string, number] = ["Foo", 15];
// Type 'boolean' is not assignable to type 'string'.(2322)
// Type 'string' is not assignable to type 'number'.(2322)
let wrongValues: [string, number] = [true, "hello"]; // Error
Since TypeScript 3.0, a tuple can specify one or more optional types using
the ? as
shown below.
let values: [string, number, boolean?] = ["Foo", 15];
88. Explain how tuple destructuring works in TypeScript.
You can destructure tuple elements by using the assignment operator (=).
The
destructuring variables get the types of the corresponding tuple elements.
let employeeRecord: [string, number] = ["John Doe", 50000];
let [emp_name, emp_salary] = employeeRecord;
console.log(`Name: ${emp_name}`); // "Name: John Doe"
console.log(`Salary: ${emp_salary}`); // "Salary: 50000"
After destructuring, you can’t assign a value of a different type to the
destructured
variable. For example,
emp_name = true; // Type 'boolean' is not assignable to type
'string'.(2322)
Null pointers are one of the most common sources of unexpected runtime
errors in
programming. TypeScript helps you avoid them to a large degree by
enforcing strict
null checks.
You can enforce strict null checks in two ways:
-providing the –strictNullChecks flag to the TypeScript(tsc) compiler
-setting the strictNullChecks property to true in the tsconfig.json
configuration file.
When the flag is false, TypeScript ignores null and undefined values in the
code. When it
is true, null and undefined have their distinct types. The compiler throws a
type error if you try to use them where a concrete value is expected.
You can mark object properties as immutable by using the readonly keyword
before the
property name. For example:
interface Coordinate {
readonly x: number;
readonly y: number;
}
When you mark a property as readonly, it can only be set when you initialize
the object.
Once the object is created, you cannot change it.
let c: Coordinate = { x: 5, y: 15 };
c.x = 20; // Cannot assign to 'x' because it is a read-only
property.(2540)
Template literal types are similar to the string literal types. You can combine
them with
concrete, literal types to produce a new string literal type. Template literal
types allow
us to use the string literal types as building blocks to create new string literal
types.
type Point = "GraphPoint";
// type Shape = "Grid GraphPoint"
type Shape = `Grid ${Point}`;
Template literal types can also expand into multiple strings via unions. It
helps us create
the set of every possible string literal that each union member can
represent.
type Color = "green" | "yellow";
type Quantity = "five" | "six";
// type ItemTwo = "five item" | "six item" | "green item" | "yellow
item"
type ItemOne = `${Quantity | Color} item`;
Inheritance allows a class to extend another class and reuse and modify the
behavior
defined in the other class. The class which inherits another class is called the
derived
class, and the class getting inherited is called the base class.
In TypeScript, a class can only extend one class. TypeScript uses the
keyword ‘extends’
to specify the relationship between the base class and the derived classes.
class Rectangle {
length: number;
breadth: number
constructor(length: number, breadth: number) {
this.length = length;
this.breadth = breadth
}
area(): number {
return this.length * this.breadth;
} }
class Square extends Rectangle {
constructor(side: number) {
super(side, side);
}
volume() {
return "Square doesn't have a volume!"
} }
const sq = new Square(10);
console.log(sq.area()); // 100
console.log(sq.volume()); // "Square doesn't have a volume!"
In the above example, because the class Square extends functionality from
Rectangle,
we can create an instance of square and call both the area() and volume()
methods.
A conditional type allows you to dynamically select one of two possible types
based on
a condition. The condition is expressed as a type relationship test.
C extends B ? TypeX : TypeY
Here, if type C extends B, the value of the above type is TypeX. Otherwise, it
is TypeY.
Function is a global type in TypeScript. It has properties like bind, call, and
apply, along
with the other properties present on all function values.
function perform(fn: Function) {
fn(10);
}
You can always call a value of the Function type, and it returns a value of
‘any’ type.
101. List some of the utility types provided by TypeScript and explain
their usage.