The Basics Flashcards

1
Q

Using template literals, how do you output to console hello math if math is stored in a name const?

A
const name = math;

console.log(`Hello ${name}`);
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Write a fully typed function called add that takes 2 parameters a and b and return the result of a + b

A
function add(a: number, b: number): number {
  return a + b;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Using the arrow function notation write a fully typed function called add that takes 2 parameters a and b and return the result of a + b. The function has to be specific to the number type.

A

const add = (a: number, b: number): number => a + b;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Can a function be assigned to a const ?

A

Yes. For example:
const add = function (a: number, b: number): number {
return a + b;
};

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Are function parameters required by default in Typescript ?

A

Yes. For instance, calling :

function add(a: number, b: number) {
  return a + b;
}
With :
add(3) // a single parameter we are missing b...

//Will raise an error.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

How can we make a parameter optional in Typescript?

A

By adding ? after the parameter. For example:

function doSomething(a: number, b?: number): number {
   //logic. We need to handle the fact that b might or might not be provided...
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is the value of an optional parameter in Typescript when it’s not provided?

A

undefined

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What is the nullish coalescing operator ?

A

??

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

What happens to Typescript types at runtime?

A

They don’t exist…

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

In Typescript what will be the type of:
let today = new Date(2023-01-01);

A

The type will be Date. This is a Typescript specific type that doesn’t exist in Javascript. In Javascript the type of today would be object.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

What is the type of name in:
const name = “math”;

A

The type will be ‘math’ because Ts infers that this is a string constant… There is only one possible value and this is called a string literal type.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is the type days in:

const days = 31;

A

31 a number literal

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What is the type of today in:
~~~
const today = new Date(2023-01-01);
~~~

A

The type is Date a Typescript specific type.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

What will be the type of nameAgain in:
~~~
const name = “math”;
const nameAgain = last;
~~~

A

The type will be ‘math’ a string literal.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

What will be the type of nameAgain in:
~~~
const name = “math”;
let nameAgain = last;
~~~

A

The type will be ‘math’ a string literal.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What will be the type of ourName in :
~~~
const myName = “math”;
const yourName = “samantha”;
const ourNames = ${myName} ${yourName};
~~~

A

The type of ourNames will be string.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

What is the type of count in:

let count;
count = 10;

A

Any

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

What is the type of result in:

function addTwo(a) {
 return a + 2;
} 

const result = addTwo(4);
A

any

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

What is the type of result in:

function addTwo(a =1) {
 return a + 2;
} 

const result = addTwo(4);
A

number

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

What is the type of result in:

let result;
A

any

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

Will this yield any error?

If not what will be the type of result?

let result; 

result = "Math";
result = 18;
result = true;
result = new Date(2023, 1, 1);
A

No error. The type is any

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

What does the type:

{ [field: string]: any }

means ?

A

It’s an object whose property names are of type string, with property values of typeany.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

What kind of type checking those Typescript do on the any type?

A

None

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

What is the type void?

A

The void type represents a function’s return type when it doesn’t return any data.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

What are the type(s) that void can be?

A

undefined or null if the strictNullChecks compiler option is off.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q

Will this raise an error?
~~~
const items = [];
items.push(1);
items.push(“two”);
items.push(false);

console.log(items);
~~~

A

No. items is of type any.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q

Will this raise an error?

const items: Array<number> = [];
items.push(1);
items.push("two");
items.push(false);
A

Yes. The type of items is number trying to push a string “two” and a boolean false is not allowed.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q

Declare a const called items and assign it a generic array of numbers and set its content to 1,2,3 at initialisation.

A
const items: Array<number> = [1,2,3];
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

Use the square bracket notation to create a const variable called items that is assigned to an array of strings containing “one”, “two”, and”three”.

A

const items : string[] = ["one","two", "three"];

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q

What will be the type of array?

const array = [1, 2, 3];
console.log(array);
A

number

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

What is items and what is items type in this sample?

function logItems(name, ...items) {
 console.log(name, items);
}
A

items is an array of type any. This type of parameter preceded by … is called a rest parameter.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q

What is a tuple?

A

A tuple can be thought of as an array with a fixed number of elements.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
33
Q

Do tuple exist in Javascript ?

A

The tuple type doesn’t exist in JavaScript. The closest we have are arrays, but there is no way of enforcing the number of elements and each element’s type.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
34
Q

Is this a tuple? What’s the type inferred ?

const score = ["Math", 95];
A

No, the type is:

(string | number)[]

So, the array can hold more than two elements

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
35
Q

How can we modify this code sample to make sure we have a tuple of with a string and number?

const score = ["Math", 95];

A

const score: [string,number] = ["Math", 95];

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
36
Q

Add a label name and score on this tuple:

const score: [string, number] = ["Math", 95];
A
const score: [name:string, score:number] = ["Math", 95];
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
37
Q

Declare a tuple const named score with 2 labeled elements. The name element which should be a string and the score element which should be a number.

A
const score: [name:string, score:number] = ["Math", 95];
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
38
Q

Create an open ended tuple called myNumbers taking a string called name and an unlimited number of numbers.

A
const myNumbers: [name:string, ...numbers:number[]] = ["Math", 95,65,89];

//...number[] is a rest element. 
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
39
Q

What is the type returned in the following function?

const keepGoing = (message: string) => {
  while (true) {
    console.log(message);
  }
};
A

The return type is never because this function never returns. That’s why it’s not returning void.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
40
Q

Name a common use for the never type?

A

To flag region of code that should never be reached. For instance, using this kind of function:

function unreacheable(never: never) {}

Typescript will raise an error if it detects that this code can be reached.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
41
Q

Create a function called unreachable that takes in a parameter of type never called never.

A

function unreacheable(never: never) {}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
42
Q

Will this function raise an error:
~~~
function add(a: unknown, b: unknown) {
return a + b;
}
~~~

A

Yes. Variables of type unknown can’t be added together.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
43
Q

Modifiy the body of this function not its signature so that we check that a and b are numbers and add them or return 0 if they are not numbers.

function add(a: unknown, b: unknown) {
  return a + b;
}
A

function add(a: unknown, b: unknown) {
if (typeof a === “number” && typeof b === “number”) {
return a + b;
}
return 0;
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
44
Q

In the following function what are the type of a and b on the line:

return a + b; ?

function add(a: unknown, b: unknown) {
  if (typeof a === "number" && typeof b === "number") {
    return a + b;
  }
  return 0;
}
A

number

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
45
Q

What are type guard?

A

The type guard allows TypeScript to adjust the types of unknown to some other type it can work with.

You can’t operate directly on variables of type unknown. We have to give TypeScript information to narrow the type so that it can be used.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
46
Q

Given this:
~~~
interface Person {
firstName: string;
surname: string;
contactType: “person”;
}
interface Organisation {
name: string;
contactType: “organisation”;
}
type Contact = Person | Organisation;
~~~
Create a isPerson function that will take a any parameter named person and checks that the person parameter is of type Person using a type predicate.

A
function isPerson(contact: Contact): contact is Person {
  return (contact as Person).firstName !== undefined;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
47
Q

Will Typescript detect a problem with this code? If so what is the problem?
~~~
const today = new Date();
console.log(today.getWeekDay());
~~~

A

The Date constructor can be called with no parameters but the Date type doesn’t contain a getWeekDay method.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
48
Q

What is the return type of this function:

function logMessage(message: string) {
  return console.log(message);
}
A

void

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
49
Q

What are correct type annotations for creating an array of dates?
~~~
1. date[]
2. Array<date>
3. Date[]
4. Array<Date>
~~~</Date></date>

A

The correct answers are:
~~~
3. Date[]
4. Array<Date>
~~~</Date>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
50
Q

What will TypeScript infer the type of the people variable to be in the declaration below?
let people = ["Paula", "Bob", "Sam"];

A

string[]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
51
Q

How can we strongly-type the messages rest parameter so that only string types can be passed?

function outputMessages(...messages) {
    messages.forEach(message => console.log(message));
}
A

function outputMessages(…messages: string[]) {
messages.forEach(message => console.log(message));
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
52
Q

The following function calls and thirdPartyCalculation method that returns any. Modify this function to use the unknown type and add a type guard to narrow down the type of result to number and return the result. Return undefined if the result is not a number.

function doWork() {
  const result = thirdPartyCalculation();
  return result + 1;
}
A
function doWork() {
  const result: unknown = thirdPartyCalculation();
  if (typeof result === "number") {
    return result + 1;
  }
  return undefined;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
53
Q

What is the type of the invalid variable in the function below?

function outputMessage(message: string) {
  if (typeof message === "string") {
    console.log(message);
  } else {
    let invalid = message;
    console.error(invalid);
  }
}
A

never

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
54
Q

We have a variable that will hold a two-dimensional point. What is most appropriate type annotation for this?

A

[number, number] is the most appropriate because is accepts 2 numbers.

The any type isn’t appropriate because no type checking will occur on the variable. number[] isn’t ideal because the array will accept more than 2 numerical values. [number] will not work because it will only accept 1 numerical value.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
55
Q

Create an enum called Level with the names Debug, Info, Error

A
enum Level  {
Debug,
Info,
Error
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
56
Q

For the following enum what will be the output value at the console for Info ?

enum Level  {
Debug,
Info,
Error
}
A

1
enums values are zero-based auto-incrementing numbers by default.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
57
Q

Will this generate an error?

enum Level  {
  Debug,
  Info,
  Error
  }

let level: Level;
level = 5;

console.log(level);
A

No, unfortunately, numeric enums accept any numeric value.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
58
Q

Set a string value for each level in the following enum:

enum Level  {
  Debug,
  Info,
  Error
  }
A
enum Level  {
  Debug = "Debug",
  Info = "Info",
  Error = "Error"
  }
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
59
Q

Will this code generate an error:

enum Level  {
  Debug = "Debug",
  Info = "Info",
  Error = "Error"
  }

  let level:Level;

  level = Level.Error;
  console.log(level);

  level = "Debug";
A

Yes. We can’t assign the enum value using the string value:
level = "debug"

Will generate an error.

The proper assignment would be:
level = Level.Debug;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
60
Q

Declare a const score with an object implicitly typed with a name “Math” and a score of 85

A
const score = {
  name: "Math",
  score: 85
};
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
61
Q

Using the explicit object type annotations specify a let variable called variable that contains a member1 of type1 and a member2 of type2.

A

let variable: { member1: type1; member2: type2};

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
62
Q

Declare a const score with an explicitly typed object with a name “Math” and a score of 85

A
const score: { name: string; score: number; } = {
  name: "Math",
  score: 85
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
63
Q

Declare a const score with an explicitly typed object with a name “Math” and a optional score left empty.

A
const score: { name: string; score?: number; } = {
  name: "Math"
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
64
Q

What is a type alias?

A

A type alias is a name that refers to another type

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
65
Q

Create a new type TypeAliasName based of an existing type called ExistingType.

A

type TypeAliasName = ExistingType;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
66
Q

Create a type alias for a string called FirstName

A

type FirstName = string;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
67
Q

Create a type alias for a number called PersonScore.

A

type PersonScore = number;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
68
Q

Can Type aliases be used for arrow functions?

A

Yes.
type TypeAliasName = (paramName1: paramType1; ...) => ReturnType;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
69
Q

Create a type alias called Log that represents this function:

Create a type alias called Log that represents this function:
const log = (message: string) => {
  console.log(message);
};
A

type Log = (message: string) => void;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
70
Q

Add Log in a type annotation to the function:
~~~
Create a type alias called Log that represents this function:
const log = (message: string) => {
console.log(message);
};
///The type:
type Log = (message: string) => void;
~~~

A
const log: Log = (message: string) => {
  console.log(message);
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
71
Q

Add an optional parameter called category to the following type:
type Log = (message: string) => void;

A
type Log = (
  message: string;
  category?: string
) => void;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
72
Q

Create a type alias called score for :
{ name: string; score: number }
In:

const score: { name: string; score: number } = {
  name: "Math",
  score: 85,
};
A

type Score = { name: string; score: number };

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
73
Q

In type alias should you use , or ; to separate type member ?

A

It’s better to use ;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
74
Q

Add an optional boolean pass property to this type:
~~~
type Score = {
name: string;
score: number;
};
~~~

A
type Score = {
  name: string;
  score: number;
  pass?: boolean;
};
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
75
Q

Can method be declared on object type?

A

Yes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
76
Q

Add a method of type Log on this Score alias:

type Score = {
  name: string;
  score: number;
  pass?: boolean;
};
A
type Score = {
  name: string;
  score: number;
  pass?: boolean;
  log: Log;
};
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
77
Q

Do interfaces exist in Javascript?

A

No.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
78
Q

What is the syntax to declare an interface ?
Use these to help you: TypeName,propertyName,PropertyType,methodName,paramName, ParamType, MethodReturnType

A
interface TypeName {
  propertyName: PropertyType;
  methodName: (paramName: ParamType) => MethodReturnType;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
79
Q

Declare a ButtonProps interface with a text string property and a onClick method that takes no parameter and return void. Use the arrow notation for the method signature.

A
interface ButtonProps {
  text: string;
  onClick: () => void;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
80
Q

Make the method onClick optional on the following interface:
~~~
interface ButtonProps {
text: string;
onClick: () => void;
}
~~~

A
interface ButtonProps {
  text: string;
  onClick?: () => void;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
81
Q

Is it possible for an interface to inherit all the properties and methods of another interface?

A

Yes. Through the use of extends.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
82
Q

Declare an interfaceA that has all the properties and methods of another interface called interfaceB

A
interface InterfaceA extends InterfaceB {
 ...
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
83
Q

Can interface be used to represent functions ?

A

Yes. Using this syntax:
~~~
interface TypeName {
(paramName1: paramType1, …): ReturnType;
}
~~~

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
84
Q

What is the syntax for an interface to represent a function? Use TypeName, paramName1, paramType1 and ReturnType to help you.

A
interface TypeName {
   (paramName1: paramType1, ...): ReturnType;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
85
Q

Declare an interface called Log for the following const:
~~~
const log = (message: string) => {
console.log(message);
};
~~~

A

interface Log {
(message: string): void;
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
86
Q

Given the interface Log:
~~~
interface Log {
(message: string): void;
}
~~~

and the const log:

const log = (message: string) => {
  console.log(message);
};

add the type annotation to log.

A
const log: Log = (message: string) => {
  console.log(message);
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
87
Q

Is it legal in Typescript to create multiple interfaces with the same names?

A

Yes. Typescript will merge the declaration with the same name. It’s called declaration merging.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
88
Q

When can it be useful to use declaration merging?

A

Mostly when using third-party libraries.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
89
Q

What are union type ?

A

They are types that we can combine to create a new type. We use the pipe | operator for this. For example:
type A_or_B_or_C = A | B | C;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
90
Q

Change the type of :
let age: number | null;
so it can be undefined as well.

A

let age: number | null | undefined;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
91
Q

Create a type alias from :
let age: number | null;

A

type Age = number | null;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
92
Q

Create a string literal union type called Fruit with possible values of:
Banana, Apple, or Pear

A

type Fruits = "Banana", "Apple", "Pear";

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
93
Q

When are string literal union types useful?

A

When we need a more specific type than string.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
94
Q

Are string literal union type case sensitive?

A

Yes.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
95
Q

Can objects be unioned as well?

A

Yes. For example:
type Actions = { type: "loading" } | { type: "loaded"; data: { name: string } };

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
96
Q

What is an intersection type and how can we express it?

A

Intersection types combine existing types to form a new type. An intersection type will have all the members from the types that it is based on. Intersection types don’t just contain the common members from the types that it is based on, as you may first expect.

type A_and_B_and_C = A & B & C;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
97
Q

What is the symbol used to declare intersection type?

A

&

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
98
Q

Create an intersection type called Contacts from these 2 types:
~~~
type Name = {
firstName: string;
lastName: string;
};
type PhoneNumber = {
landline: string;
mobile: string;
};
~~~

A

type Contact = Name & PhoneNumber;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
99
Q

What will be the type of kind in the intersected Field type ?
~~~
type BaseElement = {
name: string;
kind: “text” | “number” | “email”;
};
type TextInput = {
kind: “text”;
};
type Field = BaseElement & TextInput;
~~~

A

It will be “text” because the type of a common member of an intersection type is mathematically intersected.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
100
Q

What parameter can the type A_and_B accept?

type A = {
  doIt: (a: string) => void;
};
type B = {
  doIt: (a: string, b: string) => void;
};
type A_and_B = A & B;
A

Only a:string

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
101
Q

Can an interface represent a type primitive like string?

A

No. Only TypeAlias can do this.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
102
Q

Can an interface represent a tuple ?

A

No. Only a Type alias can do this.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
103
Q

Create a type called Names that is a array of string.

A

Copy
type Names = string[];

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
104
Q

Create an interface called Names that represents an array of string.

A
interface Names {
  [index: number]: string;
}

It’s simpler to use a type alias for this…

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
105
Q

Declare a type called Log that take a parameter message a string and return void.

A

type Log = (message: string) => void;

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
106
Q

Declare an interface called Log that take a parameter message a string and return void.

A
interface Log {
  (message: string): void;
}

It’s clearer with a type…

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
107
Q

Can interface represent union types?

A

No

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
108
Q

Declare a type and interface called Person with a name string and a score number.

A
type Person = {
  name: string;
  score: number;
};

interface Person {
  name: string;
  score: number;
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
109
Q

Can both interface and type alias be used to composed objects?

A

Yes. Type alias can be composed with the & intersection. Interface can be composed with extends.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
110
Q

Can type alias componse interfaces and vice versa ?

A

Yes. For example with & (intersection):
~~~
type Name = {
firstName: string;
lastName: string;
};
interface PhoneNumber {
landline: string;
mobile: string;
}
type Contact = Name & PhoneNumber;
~~~

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
111
Q

What will be the type of status:
~~~
type OrderStatus = “pending” | “completed”;
type DeliveryStatus = “completed” | “shipped”;
type Status = OrderStatus | DeliveryStatus;
~~~

A

Status will contain ‘pending’, ‘completed’, and ‘shipped’ because we take the union of the values in the OrderStatus and DeliveryStatus sets.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
112
Q

What will be the type of status:
~~~
type OrderStatus = “pending” | “completed”;
type DeliveryStatus = “completed” | “shipped”;
type Status = OrderStatus & DeliveryStatus;
~~~

A

The Status type will just contain ‘completed’ because we take the values where the OrderStatus and DeliveryStatus sets intersect.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
113
Q

What values does the never type contain?

A

The never type doesn’t contain any values and can be thought of as an empty set.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
114
Q

What values does the unknown type contain?

A

The unknown contains all the possible values!

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
115
Q

What will be the type of status on the if line ? And on the console.log line ?
~~~
function logStatus(status: string | null) {
if (status) {
console.log(status);
}
}
~~~

A

On the if line, the type of status is string | null.
On the console.log line, the type of status is string.

The type was narrowed to string since the if check if we have a string or a truthy value. null would be a falsy value.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
116
Q

Would this raise an error:
~~~
let jones: “Tom” | “Bob” = “Tom”;
let jane: string = “Jane”;
jane = jones;
~~~

A

No because jane is of type string, which is wider than ‘Tom’ | ‘Bob’.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
117
Q

Would this raise an error:
~~~
let jones: “Tom” | “Bob” = “Tom”;
let jane: string = “Jane”;
jones = janes;
~~~

A

Yes because the type of jones is ‘Tom’ | ‘Bob’ which is narrower than the type of jane which is string. In other words, string can’t fit into ‘Tom’ | ‘Bob’.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
118
Q

Are the type or interface names important in Typescript to determine if 2 types are equivalent?

A

No. Typescript check the structure to determine the compatibility.

119
Q

Will this raise an error ?
~~~
type Person = {
name: string;
};
interface IPerson {
name: string;
age: number;
}

let bob: Person = {
name: “Bob”,
};
let fred: IPerson = {
name: “Fred”,
age: 30,
};

bob = fred;
~~~

A

TypeScript won’t raise an error. TypeScript checks fred’s type (IPerson) has a name property, which is the requirement for bob’s type (Person).

120
Q

Will this raise an error:
~~~
type Person = {
name: string;
age: number;
};
interface IPerson {
name: string;
}

let bob: Person = {
name: “Bob”,
age: 30,
};
let fred: IPerson = {
name: “Fred”,
};

bob = fred;
~~~

A

TypeScript raises an error on this assignment. TypeScript checks IPerson has both name and age properties (which it doesn’t) because person is of type Person, which requires both these properties.

121
Q

Will this raise an error:
~~~
type Dog = {
name: string;
};
type Shape = {
name: “Circle” | “Square”;
};
let ben: Dog = {
name: “Ben”,
};
let circle: Shape = {
name: “Circle”,
};
circle = ben;
~~~

A

Yes, because the type Dog can’t be assigned to an object of type Shape. This is because the types of the name property aren’t compatible because string is wider than ‘Circle’ | ‘Square’.

122
Q

Will this raise an error?
~~~
type Dog = {
name: string;
};
type Shape = {
name: “Circle” | “Square”;
};
let ben: Dog = {
name: “Ben”,
};
let circle: Shape = {
name: “Circle”,
};
ben = circle;
~~~

A

No error. The assignment is okay because ‘Circle’ | ‘Square’ fits into string.

123
Q

Will this raise an error:
~~~
let add = (a: number, b: number): number => a + b;
let sum = (x: number, y: number): number => x + y;
sum = add;
~~~

A

No. The functions have parameters of the same type, and the return type is the same.

124
Q

Are the parameter names important when comparing alias type for functions?

A

The parameter names aren’t important - it is only the types of parameters that are checked for type compatibility.

125
Q

Will this raise an error?
~~~
let add = (a: number, b: number, c: number): number => a + b + c;
let sum = (x: number, y: number): number => x + y;
sum = add;
~~~

A

Yes the assignment raises an error because add requires more parameters than sum.

126
Q

Are the number of parameters important when comparing alias type for functions?

A

Yes.

127
Q

Will this raise an error:
~~~
let add = (a: number, b: number, c?: number): number => a + b + (c || 0);
let sum = (x: number, y: number): number => x + y;
sum = add;
~~~

A

No. The assignment is fine now. This is because add now only requires two parameters, which is the same as sum.

128
Q

Will this raise an error?
~~~
let add = (a: number, b: number, c: number): number => a + b + c;
let sum = (x: number, y: number): number => x + y;
add = sum;
~~~

A

No error. The assignment is ok because a function with two parameters fits into a function with three parameters.

129
Q

When can a variable a be assigned to another variable b?

A

If the type of b is wider than the type of a.

130
Q

When can an object a be assigned to another object b?

A

If a has at least the same members as b.

131
Q

When can a function a be assigned to another function b?

A

If each parameter in a has a corresponding parameter in b with a compatible type.

132
Q

We have the following type:

type Product = {
  name: string;
  bestBeforeDate: Date;
}

bestBeforeDate doesn’t apply to every product though. So, we want to allow this to be null or a date. What type best represents this?

type Product = {
name:string;
bestBeforeDate: Date | null;
}

type Product = {
name:string;
bestBeforeDate?: Date;
}
A
type Product = {
name:string;
bestBeforeDate: Date | null;
}

A union type can be used to represent a date or a null value. Making a property optional will mean it can be set to undefined or not supplied at all, which is not the requirement. Also, making a property optional doesn’t allow it to accept null values.

133
Q

What is the type of name and price in the following class:
~~~
class Product {
name;
price;
}
~~~

A

both are any

134
Q

In Typescript strict mode will this generate an error? If so what error?
~~~
class Product {
name: string;
price: number;
}
~~~

A

The fields have been defined as required fields, but the class can be instantiated with these fields being undefined.

In TypeScript, if strict mode is on, fields must be given an initial value or be optional

135
Q

Make the field optional on this class:
~~~
class Product {
name:string;
price:number;
}
~~~

A
class Product {
  name?:string;
  price?:number;
}
136
Q

Create a const table that will be an instance of this class:
~~~
class Product {
name?: string;
price?: number;
}
~~~

A

const table = new Product();

137
Q

Refactor the following class to make the fields required and initialize them in a constructor:
~~~
class Product {
name?: string;
price?: number;
}
~~~

A
class Product {
  name: string;
  price: number;
 constructor(name: string, price: number) {
    this.name = name;
    this.price = price;
  }
}
138
Q

If we remove the types on the fields in the following class what will be the type assigned to each by TypeScript?

class Product {
  name:string;
  price:number;
  
constructor(name:string, price:number){
    this.name = name;
    this.price = price;
}

}
A

name is a string and price is a number.

139
Q

Add a static method called equal on this class to check if 2 classes of Product are equal.
~~~
class Product {
name:string;

constructor(name:string){
this.name = name;
}
}
~~~

A
class Product {
  name:string;
  
constructor(name:string){
    this.name = name;
}

  static equal(product1:Product, product2:Product) {
    return product1.name === product2.name;
  }

}
140
Q

What is the key difference between classes and -> interfaces and type aliases ?

A

Classes create object structures like type aliases and interfaces do.

A key difference is that a class may contains method implementation, whereas type aliases and interfaces don’t.

Classes can also be instantiated and execute logic during this process.

Type aliases and interfaces can’t be instantiated because they only contain structural information.

So, a class is useful for representing an object blueprint that contains constructor and method implementation.

141
Q

Will this generate an error:

class Product {
name:string;

constructor(name:string){
this.name = name;
}
}

const table1 = new Product(“Table1”, 300);

table1.price = 100;

A

No. By default the fields are public. No error are raised.

142
Q

Make the price field readonly in the follwing class:
~~~
class Product {
name:string;

constructor(name:string){
this.name = name;
}
}
~~~

A
class Product {
  readonly name:string;
  
constructor(name:string){
    this.name = name;
}
}
143
Q

Will this code raise an error:
~~~
class Product {
readonly name:string;

constructor(name:string){
this.name = name;
}
}

const table1 = new Product(“Table1”, 300);
table1.price = 100;
~~~

A

Yes. We can’t assign a value to a readonly field.

144
Q

Will this code raise an error:
~~~
class Product {
private name:string;

constructor(name:string){
this.name = name;
}
}

const table1 = new Product(“Table1”, 300);
table1.price = 100;
~~~

A

yes, because price is private and not accessible by the consumer of the class.

145
Q

If you compile this code what will be the value of price? Is it changed?
~~~
class Product {
private name:string;

constructor(name:string){
this.name = name;
}
}

const table1 = new Product(“Table1”, 300);
table1.price = 100;
~~~

A

Yes, the price is changed. The check is a type check and doesn’t occur at runtime.

TypeScript access modifiers don’t take any effect on the code at runtime.

146
Q

Refactor this class to use constructor assignement:

class Product {
  private name:string;
  
constructor(name:string){
    this.name = name;
}
}
A

class Product {

constructor(private name:string){
}
}

147
Q

What is the syntax for method overloading and what is the implementation signature and it’s role…?

A
methodName(params1): returnType1
methodName(params2): returnType2
methodName(params3): returnType3 // implementation signature
{
  // implementation
}

The last signature, just above the implementation, is called the implementation signature.

The parameter types and the return types in the signatures can be different, but they need to be compatible with the implementation signature. The implementation needs to check what parameters have been passed and take the necessary action.

148
Q

Will this method overload generate an error?
```
filter(name:string): Product[]
filter(name:string,price:number): Product[]{
return this.products.filter((filter) => filter.name === name && filter.price === price);

}
~~~

A

Yes. The error message is on the signature we just added and is ‘This overload signature is not compatible with its implementation signature’. The implementation signature expects a price parameter, but our overload doesn’t include this.

149
Q

How would you fix this method overload to resolve the error?
```
filter(name:string): Product[]
filter(name:string,price:number): Product[]{
//your logic.
}
~~~

A

The overload signatures need to fit into the implementation signature. This generally means that some of the implementation signature parameters need to be optional.

```
filter(name:string): Product[]
filter(name:string,price?:number): Product[]{
//your logic.
}
~~~

150
Q

Will this generate an error:
~~~
filter(name: string): Product[]
filter(name: string, price?: number): Product[] {
if (price === undefined) {
return this.products.filter(product => product.name === name);
} else {
return this.products.filter(
product => product.name === name && product.price === price
);
}
}
Copy
console.log(products.filter(“Table”, 300));
~~~

A

YES ! The problem is that the price argument is not recognized because this isn’t in an overload signature. This can be surprising for programmers coming from other programming languages.

151
Q

How can we fix the error generated by this code:
~~~
filter(name: string): Product[]
filter(name: string, price?: number): Product[] {
if (price === undefined) {
return this.products.filter(product => product.name === name);
} else {
return this.products.filter(
product => product.name === name && product.price === price
);
}
}
Copy
console.log(products.filter(“Table”, 300));
~~~

A

We need to add the missing overload:

filter(name: string): Product[]
**filter(name: string, price: number):  Product[];**
filter(name: string, price?: number): Product[] {
  if (price === undefined) {
    return this.products.filter(product => product.name === name);
  } else {
    return this.products.filter(
      product => product.name === name && product.price === price
    );
  }
}
152
Q

Can a class extend another class?

A

Yes.

153
Q

What is the syntax to extend a class with another class? Create a class MyClass that extends another class called MyBaseClass

A
class MyClass extends MyBaseClass {
  ...
}
154
Q

Will this code raise an error if so why?

class Product {
  constructor(public name: string, public price: number) {}
}

class Table extends Product {
  constructor(public name: string, public price: number, public legs: number) {}
}
A

We need to invoke the constructor in the Product class by calling super:

class Table extends Product {
  constructor(public name: string, public price: number, public legs: number) **{
    super(name, price);
  }**
}
155
Q

How can you override a method in a class that extends another class?

A

Simply declare a method with the same name, parameters and signature in the class that extends the base class.

156
Q

There are times when we don’t want consumers to create instances of a class. Which kind of class should we use in that case?

A

We should use an abstract class:
~~~
abstract class ClassName {

}
~~~

157
Q

What is the difference between private and protected fields?

A

The protected modifier acts much like the private modifier with the exception that members declared protected can also be accessed within deriving classes.

158
Q

Declare a const called gen for a generic type called GenericType that takes 2 Specific types: SpecificType1 and SpecificType2

A

const gen = GenericType<SpecificType1, SpecificType2, ...>

159
Q

Create a const called coordintates and assign it to an array of coordinate using this type:

type Coordinate = [number, number];

A

let coordinates: Array<Coordinate>;</Coordinate>

160
Q

Will this yield an error:
type Coordinate = [number, number];

let coordinates: Array<Coordinate>;

coordinates = [
  [30, 100, 0],
  [100, 50],
];
A

Yes, because each coordinate can only have 2 dimensions.

161
Q

Create a const called result that is a generic promise to return something of type Response.

If you don’t know the Type Response see:
https://developer.mozilla.org/en-US/docs/Web/API/Response

A

const result: Promise<Response>;

This is useful when fetching information from api like so:

const promisedResponse: Promise<Response> = fetch("https://myapi.dev/api/");

162
Q

How can we use the result of this to output if the response was OK?

const promisedResponse: Promise<Response> = fetch("https://swapi.dev/api/");</Response>

A

promisedResponse.then((res) => console.log(res.ok));

163
Q

How can we narrow the type of the record keys so that only ‘rodj’ or ‘janes’ are accepted?
~~~
type Result = {
firstName: string;
surname: string;
score: number;
};
type ResultRecord = Record<string, Result>;

const records: ResultRecord = {
rodj: {
firstName: “Rod”,
surname: “James”,
score: 70,
},
janes: {
firstName: “Jane”,
surname: “Smith”,
score: 95,
}

};
~~~

A

By changing the ResultRecord type definition from:
type ResultRecord = Record<string, Result>;

to:
type ResultRecord = Record<**"rodj"|"janes"**, Result>;

164
Q

Make this function generic:
function firstOrNull(array: string[]): string | null {
return array.length === 0 ? null : array[0];
}

A

function firstOrNull<T>(array: T[]): T | null {</T>

return array.length === 0 ? null : array[0];
}

165
Q

Declare an array and bind it to a variable called myArray for the class Item without using new Array:
~~~
class Item {
name: string;
desc: string;
meta: string
}
~~~

A

let myArray : Product[];

Note: if you use const you have to initialize the array like so:

const myArray: Product[] = [];

166
Q

Can interfaces be generic and accept multiples types ?

A

Yes. A common use if for forms.

167
Q

Create a typed const contactForm using these 2 interfaces:

interface Form<T> {
  values: T;
}

interface Contact {
  name: string;
  email: string;
}
A
const contactForm: Form<Contact> = {
    values: {
        name: "Bob",
        email: "bob@someemail.com"
    }
}
168
Q

Explain this interface and what the K in keyof T is…

interface Form<T> {
  errors: {
    [K in keyof T]?: string;
  };
  values: T;
}
A
  1. The type is in curly brackets, so we are constructing an object type.
  2. [K in keyof T] will put all the keys in the type T into a string literal union. This will be “name” | “email” for contactForm.
  3. [K in keyof T] is the property name of the object being constructed (T).
  4. The ? after the property name means the properties are optional.
  5. The type for the properties is string.

So given a T that would be an interface:
~~~
interface Contact {
name: string;
email: string;
}
~~~

The type for the errors is {name?: string; email?: string}.

169
Q

Is it possible to pass types into a type alias ?

A

Yes. Using this syntax:
~~~
type TypeName<T1, T2, …> = {

}
~~~

170
Q

Implement a generic Form type with 2 properties values for our generic T and optional errors for each key of T

A

type Form<T> = {
errors: { [K in keyof T]?: string };
values: T;
};</T>

171
Q

Can we declare generic classes ?

A

Yes

172
Q

What is the syntax to create a generic class using T1,T2,T3..

A

class ClassName<T1, T2, …> {

}

173
Q

Create a generic calls List that will take a single T and keep the items in a private items array of T.

A

class List<T> {
private items: T[] = [];
}</T>

174
Q

Add a add method on this class to add an item of type T.

class List<T> {
  private items: T[] = [];
}
A
class List<T> {
  private items: T[] = [];

**  add(item: T){
    this.items.push(item);
  }**
}
175
Q

Can generic parameter have a default value?

A

Yes

176
Q

How do we specify a default on a generic type T ?

A

<T = DefaultType>

177
Q

Will this raise any error?
~~~
interface Component<T1 = string, T2 = any> {
name: T1;
props: T2;
log: () => void;
}

const button: Component = {
name: “Button”,
props: {
text: “Save”,
},
log: () => console.log(“Save button”),
};

console.log(button.props.text);
console.log(button.props.text2);
~~~

A

No. Because absolutely no type checking is done on T2 since it’s any.

Note: When a generic parameter default is used, the type might be wider than necessary.

178
Q

Will this yield an error:
[function firstOrNull<T>(array: T[]): T | null {
return array.length === 0 ? null : array[0];
}</T>

const first = firstOrNull([1, 2, 3]);
console.log(first);
](http://)

A

No. Even if we didn’t supply the generic parameter to the function. Generic parameters aren’t required on functions. In this case, the parameter has been inferred to be number.

179
Q

Supply a default type of string for T in this function:
[function firstOrNull<T>(array: T[]): T | null {
return array.length === 0 ? null : array[0];
}](http://)</T>

A

function firstOrNull<T = string>(array: T[]): T | null {

}

180
Q

Given this code:
~~~
function firstOrNull<T = string>(array: T[]): T | null {
return array.length === 0 ? null : array[0];
}

const first = firstOrNull([1, 2, 3]);
console.log(first);
~~~

What will be the type of first?

A

first has been inferred to be number. The default generic parameter type was overridden by the type inference of the function parameters.

181
Q

Is it possible to require generic parameters to have a particular structure?

A

Yes

182
Q

How do we put a constraint of ConstrainingType on a generic parameter T?

A

<T extends ContrainingType>

183
Q

Will this raise an error? If so why?

interface Logable {
  log: () => void;
}

function logItems<T>(items: T[]): void {
  items.forEach(item => item.log());
}
A

Yes. TypeScript doesn’t know that the array items contain a log method, so, it raises an error.

184
Q

This function will raise an error since Typescript doesn’t know that the item implement .log(). Fix this by adding a parameter constraints on the generic type.

interface Logable {
  log: () => void;
}

function logItems<T>(items: T[]): void {
  items.forEach(item => item.log());
}
A
interface Logable {
  log: () => void;
}

function logItems<**T extends Logable**>(items: T[]): void {
  items.forEach(item => item.log());
}
185
Q

Can a generic parameter constraint be dependent on another generic parameter?

A

Yes

186
Q

This raise an error. Why?
~~~
interface Form<T> {
values: T;
}
function getFieldValue<T>(form: Form<T>, fieldName: string) {
return form.values[fieldName];
}
~~~</T></T></T>

A

TypeScript doesn’t know what the structure of value is, so, it raises an error.

187
Q

This raise an error:
~~~
interface Form<T> {
values: T;
}
function getFieldValue<T>(form: Form<T>, fieldName: string) {
return form.values[fieldName];
}
~~~</T></T></T>

Fix it using parameter constraint.

A
interface Form<T> {
  values: T;
}
function getFieldValue<T**, K extends keyof T**>(form: Form<T>, fieldName**: K**) {
  return form.values[fieldName];
}

Note: The TypeScript keyof keyword queries the keys of the type referenced after it.

188
Q

What is the rest element?

A

A rest element type is a type for a collection of tuple elements.

189
Q

Is it possible to use generic rest elements?

A

Yes. For example:
type NameAndThings<T extends unknown[]> = [string, ...T];

190
Q

Add labels to make the structure of the tuple a little more readable. Add a label name and things to this code:
type NameAndThings<T extends unknown[]> = [string, ...T];

A

type NameAndThings<T extends unknown[]> = [name: string, …things: T];

191
Q

Using this type:
type NameAndThings<T extends unknown[]> = [name: string, ...things: T];
Declare a let variable to hold the following numeric scores for bob: 4,5 and pass in bob’s name.

A
let bobScores: NameAndThings<number[]>;
bobScores = ["Bob", 4, 9, 3];
192
Q

Using this function declare a variable to hold grades scores for Bill using our NameAndThings type. The tuple should contain a string-based name in the first element and grades in subsequent elements. The grades can only be ‘A’, ‘B’, or ‘C’.
type NameAndThings<T extends unknown[]> = [name:string, ...things:T];

A
type NameAndThings<T extends unknown[]> = [name:string, ...things:T];

type Grade = "a"|"b"|"c";

let billGrades : NameAndThings<Grade[]>;
  billGrades = ["bill","a","b","c"]
or 

let billGrades: NameAndThings<("A" | "B" | "C")[]>;

193
Q

Will this raise an error:
~~~
function logThings<T extends unknown[]>(name: string, …things: T) {
console.log(things);
}

logThings(“Bob”, 4, 9, 3);
~~~

A

No. TypeScript cleverly infers the generic parameter type from the parameter values.

194
Q

Will this raise an error:

function logThings<T extends unknown[]>(name: string, ...things: T) {
  console.log(things);
}

logThings("Bob", 4, "9", 3);
A

No, TypeScript infers the generic parameter type to be [number, string, number].

195
Q

Will this raise an error:
~~~
function logThings<T extends unknown[]>(name: string, …things: T) {
console.log(things);
}

logThings<number[]>(“Bob”, 4, “9”, 3);
~~~

A

Yes, because ‘9’ is not a number type.

196
Q

Can function parameter be thought of as a tuple?

A

Yes. Typing function parameters as a tuple allow strongly-typed functions to be created that have varying parameters.

197
Q

What will be the type of scores in:
~~~
function merge(names: string[], scores: number[]) {
return […names, …scores];
}

let scores = merge([“Bill”, “Jane”], [8, 9]);
~~~

A

(string | number)[]

198
Q

What are Names and Scores in this function:
~~~
function merge<Names extends string[], Scores extends number[]>(
names: Names,
scores: Scores
) {
return […names, …scores];
}
~~~

A

Generic parameter types

199
Q

What is the type of scores here:
~~~
function merge<Names extends string[], Scores extends number[]>(
names: Names,
scores: Scores
) {
return […names, …scores];
}

let scores = merge([“Bill”, “Jane”], [8, 9]);
~~~

A

(string | number)[]

200
Q

What is the type of scores here:
~~~
function merge<Names extends string[], Scores extends number[]>(
names: […Names],
scores: […Scores]
) {
return […names, …scores];
}

let scores = merge([“Bill”, “Jane”], [8, 9]);
~~~

A

(‘Bill’ | ‘Jane’ | 8 | 9)[]

201
Q

We are using the spread operator here to specify the return type. What will be the type of scores:
~~~
function merge<Names extends string[], Scores extends number[]>(
names: […Names],
scores: […Scores]
): […Names, …Scores] {
return […names, …scores];
}

let scores = merge([“Bill”, “Jane”], [8, 9]);
~~~

A

[‘Bill’, ‘Jane’, 8, 9]

202
Q

We have a function below which outputs the name property of an object to the console. How can we use generics to make this more strongly-typed?

function logName(object: any) {
  console.log("My name is " + object.name);
}
A

function logName<T extends {name: string}>(object: T) {
console.log(“My name is “ + object.name);
}

203
Q

Will this raise an error?

type Animal = {
  name: string;
  legs?: number;
};

function addLeg(animal: Animal) {
  animal.legs = animal.legs + 1; 
}
A

Yes
~~~
type Animal = {
name: string;
legs?: number;
};
function addLeg(animal: Animal) {
animal.legs = animal.legs + 1; // 💥 - Object is possibly ‘undefined’
}
~~~

204
Q

What is type narrowing?

A

Moving from a less precise type to a more precise type.

205
Q

What is the type of button here:
const button = document.querySelector(".go");

A

Element | null

206
Q

Will a type error occur here if so why?
~~~
const button = document.querySelector(“.go”);

if (button) {
button.disabled = true;
}
~~~

A

Yes. Here the type of button will be Element | null and these don’t have a disabled property.

207
Q

How can we narrow the type of button here using <> to HTMLButtonElement:
const button = document.querySelector(".go");

A

const button = <HTMLButtonElement>document.querySelector(".go");

208
Q

How can we narrow the type of button here using the as syntax to HTMLButtonElement:
const button = document.querySelector(".go");

A

const button = document.querySelector(".go") as HTMLButtonElement;

209
Q

Which syntax is preferred for type narrowing? The <type> or as syntax?</type>

A

The as syntax is preferred

210
Q

Will Typescript be able to infer that text is not null on the return line here?
~~~
function duplicate(text: string | null) {
let fixString = function() {
if (text === null || text === undefined) {
text = “”;
}
};
fixString();

return text.concat(text);
}
~~~

A

No. In this case Ts can’t infer the type. The easier solution is to use the non-null assertion operator !
~~~
function duplicate(text: string | null) {
let fixString = function() {
if (text === null || text === undefined) {
text = “”;
}
};
fixString();

return text!.concat(text!);
}
~~~

211
Q

What is the Non-null assertion operator syntax?

A

The non-null assertion operator is an exclamation mark (!), and this is placed after the variable or expression that we want to tell TypeScript isn’t null or undefined. We should only use this when we definitely know the variable or expression can’t be null or undefined.

212
Q

What is the type of item in the if branch? And in the else branch?
~~~
function double(item: string | number) {
if (typeof item === “string”) {
return item.concat(item);
} else {
return item + item;
}
}
~~~

A

string in the if branch and else in the else branch.

213
Q

What will be the type detected by your IDE here? And what will be the output to the console?
~~~
const wtv = “myname”;
console.log(typeof wtv);
~~~

A

Here the type is the string litteral “myname” but the output will be string. Why? Because typeof is a Javascript runtime operator and doesn’t about Typescript type at runtime (they are stripped).

214
Q

What is typeof and when is it useful?

A

It is useful for type guard and is called a typeof type guard. It’s useful on variables or expressions with primitive types.

215
Q

What is the instanceof operator?

A

instanceof is a JavaScript operator that can check whether an object belongs to a particular class. It also takes inheritance into account.

216
Q

Using instanceof How would you add the missing todo knowing that Person and Organisation extend Contact?
~~~
function sayHello(contact: Contact) {
// TODO - Output Hello {firstName} if a person
// TODO - Output Hello {name} if an organisation
}
~~~

A

By using the instanceof operator:

function sayHello(contact: Contact) {
  if(contact instanceof Person){
    console.log(contact.firstName);
  }else if(contact instanceof Organisation){
    console.log(contact.name);
  }
}
217
Q

What is the in operator? What is the syntax used?

A

in is a JavaScript operator that can be used to check whether a property belongs to a particular object.

The syntax is:

propertyName in objectVariable;

218
Q

How would you solve this using the in operator? Knowing firstName is a field of defined on the Person interface and name is a field defined on a Organisation interface and Contat is defined:
~~~
type Contact = Person | Organisation;

function sayHello(contact: Contact) {
// TODO - Output Hello {firstName} if a person
// TODO - Output Hello {name} if an organisation
}
~~~

A
function sayHello(contact: Contact) {
  if ("firstName" in contact) {
    console.log("Hello " + contact.firstName);
  }
	  if ("name" in contact) {
    console.log("Hello " + contact.name)
  }
}

Note this is error prone. If there is a typo in the name Typescript won’t always raise an error and you can end up with a Record or something else in the branch.

219
Q

What is a user-defined type guard with a type predicate?

A
function isTypeName(paramName: WideTypeName): paramName is NarrowTypeName {
  // some check
  return boolean_result_of_check;
}

Note:paramName is NarrowTypeName is the type predicate in the above function.

A type guard function must return a boolean value if a type predicate is used.

220
Q

Given this:
interface Person {
firstName: string;
surname: string;
}
interface Organisation {
name: string;
}
type Contact = Person | Organisation;

Create a user defined type guard with a type predicate an called the function isPerson.
Perform the check on firstName.

A

function isPerson(contact: Contact): contact is Person {
return (contact as Person).firstName !== undefined;
}

221
Q

What is an an assertion signature?

A

An assertion signature can be used in a function’s return type to indicate the narrowed type of the parameter:
~~~
function assertTypeName(
paramName: WideTypeName
): asserts paramName is NarrowTypeName {
if (some_check) {
throw new Error(“Assert failed”);
}
}
~~~

If the function returns without an error being raised, then the paramName is asserted to be of type NarrowTypeName.

222
Q

Given this :
~~~
interface Person {
firstName: string;
surname: string;
}
interface Organisation {
name: string;
}
type Contact = Person | Organisation;

function assertIsPerson(contact: Contact): asserts contact is Person {
if ((contact as Person).firstName === undefined) {
throw new Error(“Not a person”);
}
}
~~~

Write a sayHello function that takes a contact parameter and use asserIsPerson before outputing Hello contact.firstName to the console.

A
function sayHello(contact: Contact) {
  assertIsPerson(contact);
  console.log("Hello " + contact.firstName);
}

Note: We do not put assertIsPerson in a if check. The function does not return a bool it returns void and throws an error if the type is wrong.

223
Q

Explain the discriminated union pattern.

A

The discriminated union pattern has three key parts:

1.The first part of the pattern is to have a common singleton type property. A singleton type is one that contains only a single value. An example of a singleton type is a string literal. This part of the pattern is called the discriminant:
~~~
type Type1 = {

commonName: “value1”
}
type Type2 = {

commonName: “value1”
}

type TypeN = {

commonName: “valueN”
}
~~~
2. The second part of the pattern is to have a union type of all the singleton types used. This part of the pattern is called the union:
type UnionType = Type1 | Type2 | ... | TypeN
3. The final part of the pattern is to have type guards on the common property which narrows the union type:
~~~
function (param: UnionType) {
switch (param.commonName) {
case “value1”:
// type narrowed to Type1
break;
case “value2”:
// type narrowed to Type2
break;

case “valueN”:
// type narrowed to TypeN
break;
}
}
~~~

224
Q

What is the discriminant property in the Person and Organisation types?
~~~
interface Person {
firstName: string;
surname: string;
contactType: “person”;
}
interface Organisation {
name: string;
contactType: “organisation”;
}
type Contact = Person | Organisation;
~~~

A

The common property is contactType.

225
Q

What is the type of contact on the console.log line:
~~~
interface Person {
firstName: string;
surname: string;
contactType: “person”;
}
interface Organisation {
name: string;
contactType: “organisation”;
}
type Contact = Person | Organisation;

function sayHello(contact: Contact) {
switch (contact.contactType) {
case “person”:
console.log(“Hello “ + contact.firstName);
break;
}
}
~~~

A

Person

226
Q

Which is the correct syntax to check the type of a and b is a number?

1.
~~~
function add(a:unknown, b:unknown):number{
if( typeof a === “number” && typeof b === “number”){
return a + b;
}
return 0;
}
~~~

2.
~~~
function add(a:unknown, b:unknown):number{
if( a typeof === “number” && b typeof === “number”){
return a + b;
}
return 0;
}
~~~

A
  1. is the correct answer.
    typeof a === "number"

typeof has to precede the variable we are checking.

227
Q

What are mapped types?

A

Mapped types allow us to create new types from existing types.

We can think of a mapped type as the array map function, but it maps types rather than values.

228
Q

What is the syntax to use the keyof operator? What does it do?

A

let keys: keyof ExistingType;

The keyof operator to extract the keys from an object in a type annotation. When TypeScript sees the keyof operator in a type annotation, it queries the type after it and extracts all its keys. It then constructs a union string literal type from the keys.

Note: The keyof operator is sometimes referred to as the index query operator because it queries the type specified after it.

229
Q

What are people referring to when they talk about the the index query operator?

A

The keyof operator.

230
Q

Use the keyof operator to extract the keys of this type to a let variable called keys:
type ContactDetails = { name: string; email: string };

A

let keys : keyof ContactDetails;

231
Q

What is the type of keys here:
~~~
type ContactDetails = { name: string; email: string };
let keys : keyof ContactDetails;
~~~

A

The type of keys is ‘name’ | ‘email’. Note that in recent versions of TypeScript, when you hover over keys, the type will be printed as keyof ContactDetails.

232
Q

What is a mapped type?

A

A mapped type is the process of creating a new type by mapping type information from an existing type.
type MappedTypeName = { [K in UnionType]: ExistingType };

233
Q

What is this code for and explain what it does:
type NewTypeName = { [K in UnionType]: ExistingType };

A

This is a MappedTypeName.

The in operator maps over each item in the union type to create a new type. In other words, the in operator allows us to loop through each type in a union type. In a loop iteration, wach item in the union type is put in K, which becomes a key in the new type. So, the union type is usually a union of string literals. The type annotation in the mapped type is the type given to each key in the type.

234
Q

What will be the output of the type being created here:
type ContactDetails = { [K in "name" | "email"]: string };

A
{
  name: string;
  email: string;
}
235
Q

Is there an error in this code? Update this code so that errors can only have the field name with values that also exist in T. Use the keyof operator.
~~~
interface Form<T> {
values: T;
errors: any;
}</T>

const contactForm: Form<{ name: string; email: string }> = {
values: {
name: “Bob”,
email: “bob@someemail.com”
},
errors: {
emailAddress: “Invalid email address”
}
};
console.log(contactForm);
~~~

A

We provided an invalid error since email is not in the generic Form possible fields: name and email.
~~~
interface Form<T> {
values: T;
errors: { [K in keyof T]?: string };
}</T>

const contactForm: Form<{ name: string; email: string }> = {
values: {
name: “Bob”,
email: “bob@someemail.com”
},
errors: {
email: “Invalid email address”
}
};
console.log(contactForm);
~~~

We need to make the mapped keys optional with ? Otherwise we will have an error.

236
Q

Name some mapped type modifier and their use.

A

The ? to make the keys in the mapped type optional. the readonly modifier to make the field readonly and the - symbol to change a readable to writable (-readonly) and -? to make a property writtable.

{
  [K in keyof T]-?: TypeName
}

{
  -readonly [K in keyof T]: TypeName
}
237
Q

Create a RequiredProperties generic type that makes optional properties required. Use this type to map to another const called requiredBob. Use this sample:
~~~
type Contact = {
name: string;
email?: string;
};

const bob: Contact = {
name: “Bob”,
email: “bob@bob.com
};

console.log(bob);
~~~

A

type Contact = {
name: string;
email?: string;
};

type RequiredProperties<T> = {
[K in keyof T]-?:string;
};</T>

const bob: Contact = {
name: “Bob”,
email: “bob@bob.com”
};

const requiredBob: RequiredProperties<Contact> = {
name: "Bob",
email: "bob@bob.com"
};</Contact>

238
Q

Will this generate an error. If so what is the error:
type Contact = {
name: string;
email?: string;
age?: number;
};

type RequiredProperties<T> = {
[K in keyof T]-?:string;
};</T>

const requiredBob: RequiredProperties<Contact> = {
name: "Bob",
email: "bob@bob.com"
};</Contact>

A

The mapped type gives all the keys a string type, but we have specified a number for age.

239
Q

Create a generic type called RequiredProperties that take one type T and make the optional properties required and preserve the type of each key valye.

A

type RequiredProperties<T> = {
[K in keyof T]-?: T[K];
};</T>

We have changed the key type from string to T[K]. This gets the corresponding type from the type being mapped from. It is called a lookup type or sometimes an indexed access type.

240
Q

What is the standard utility Required and what does it do.
Recreate it yourself.

A

It’s a mapped type that makes optional properties required and preserve the type of the key value:
~~~
type Required<T> = {
[P in keyof T]-?: T[P];
};
~~~</T>

241
Q

What is a lookup type or an indexed access type?

A

In mapped types it allows to get the corresponding type being mapped from:
~~~
type RequiredProperties<T> = {
[K in keyof T]-?: T[K];
};
~~~</T>

The :T[K] is what we are referring to.

242
Q

What is the typeof annotation?

A

The syntax for using a typeof operator in a type annotation is as follows:
let newObject: typeof existingObject;

When TypeScript sees the typeof operator in a type annotation, it queries the object after it and extracts its type. So, in the example above, the type of existingObject is given to the newObject variable.

This syntax can be used on function parameters as well:
function (param: typeof existingObject) { ... }

243
Q

Use the typeof annotation to create a let newObject of type existingObject.

A

let newObject: typeof existingObject;

244
Q

Can the typeof annotation be used on a function parameter? If so how?

A

Yes.
function (param: typeof existingObject) { ... }

245
Q

Use the typeof annotation to specify the type of details in the function:
~~~
const initialContactDetails = { name: “”, email: “” };

function saveContactDetails(details) {
console.log(details);
}
~~~

A
function saveContactDetails(details: typeof initialContactDetails) {
  console.log(details);
}
246
Q

What type is structurally the same as PersonKeys in this sample:

type Person = {
  firstName: string;
  surname: string;
  greet: () => void;
}
type PersonKeys = keyof Person;

'firstName' | 'surname' | 'greet'
or
'firstName' | 'surname'
or
` ‘greet’`

A

'firstName' | 'surname' | 'greet'

keyof extracts all the keys from an object including properties and methods.

247
Q

Structurally, which type is equivalent to the type below?

type Votes = {
    [K in "apple" | "banana" | "strawberry"]: number
}

This:
~~~
{
apple: number;
banana: number;
strawberry: number;
}
~~~

or

["apple", "banana", "strawberry"];

or

string[]

A

["apple", "banana", "strawberry"];

248
Q

Create a Writable generic mapped type that removes all the readonly modifiers from this object:

type Person = {
  readonly name: string;
  readonly age: number;
}
A
type Writable<T> = {
    -readonly [P in keyof T]: T[P];
}
249
Q

What are conditional types ?

A

Conditional types are useful for removing type within a type.
Types that we create can have conditional logic, just like regular JavaScript code.
T1 extends T2 ? A : B

The extends keyword is used to define the condition. If T2 is within T1 then type A is used; otherwise, type B is used.

250
Q

What is NonNullable ?

A

It’s a standard utility type in TypeScript that is implemented using a conditional type to remove null and undefined from the type passed into it.

251
Q

What will Example1 resolve to:
~~~
type Person = {
name: string;
age: number;
};
type Example1 = Person extends {} ? string : number;
~~~

A

string
Note: this is an example of a conditional type.

252
Q

Create a utility type that remove null using conditional type. Name your type RemoveNull

A

type RemoveNull<T> = T extends null ? never : T;</T>

253
Q

What is the use of the infer keyword?

A

There is an infer keyword that can be used within a condition in a conditional type to put the inferred type into a variable. That inferred variable can then be used within the conditional branches.

254
Q

What will be the type of item1 and item2 here:
~~~
type ArrayElementType<T> = T extends (infer E)[] ? E : T;</T>

type item1 = ArrayElementType<number[]>;

type item2 = ArrayElementType<{ name: string }>;
~~~

A

item1 is number
item2 is {name: string}

255
Q

Review this conditional type…
~~~
function addPerson(personName: string) {
return {
type: “AddPerson”,
payload: personName
};
}

function removePerson(id: number) {
return {
type: “RemovePerson”,
payload: id
};
}

type AddPersonType = typeof addPerson;
type RemovePersonType = typeof removePerson;

type FunctionReturnType<T> = T extends (...args: any) => infer R ? R : T;</T>

type Actions =
| FunctionReturnType<AddPersonType>
| FunctionReturnType<RemovePersonType>;</RemovePersonType></AddPersonType>

type Actions =
| FunctionReturnType<AddPersonType>
| FunctionReturnType<RemovePersonType>;</RemovePersonType></AddPersonType>

~~~

What is the type Actions equivalent to?

A

Actions is equivalent to the type below:

{
  type: string;
  payload: string;
} | {
  type: string;
  payload: number;
}

Note: this will work even if you are using an object instead of a function.

Here is a version that works only on functions:

function addPerson(personName: string) {
  return {
    type: "AddPerson",
    payload: personName
  };
}

function removePerson(id: number) {
  return {
    type: "RemovePerson",
    payload: id
  };
}

type AddPersonType = typeof addPerson;
type RemovePersonType = typeof removePerson;

type FunctionReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : T;

type Actions =
  | FunctionReturnType<AddPersonType>
  | FunctionReturnType<RemovePersonType>;
256
Q

What is this doing?~~~type ReturnType<T extends (…args: any) => any> = T extends ( …args: any) => infer R ? R
: any;
~~~

A

Gives the return type of the function.

257
Q

What is ReturnType

A

It is a standard TypeScript utility type. It return the return type of a function.

258
Q

What will be the type of ContactKeys in:
~~~
const person = {
name: “Fred”,
age: 30,
email: “fred@somewhere.com”
};

console.log(person);

type RemoveFromUnion<T, K> = T extends K ? never :T;

type ContactKeys = RemoveFromUnion<keyof typeof person, “age”>;
~~~

A

‘name’ | ‘email’

Note our RemoveFromUnion is the same as the standard utility type called Exclude.

259
Q

What will be the type of Contact here:
~~~
const person = {
name: “Fred”,
age: 30,
email: “fred@somewhere.com”
};

type ObjectWithKeys<T, K extends keyof T> = {
[P in K]: T[P];
};

type Contact = ObjectWithKeys<typeof person, “name” | “email”>;
~~~

A

{ name: string; email: string; }

Note: This is the same type as a standard utility type called Pick.

260
Q

What will be the type of Profile here:
~~~
const person = {
name: “Fred”,
age: 30,
email: “fred@somewhere.com”
};

type ObjectWithKeys<T, K extends keyof T> = {
[P in K]: T[P];
};

type Contact = ObjectWithKeys<typeof person, “name” | “email”>;

type RemoveFromUnion<T, K> = T extends K ? never : T;

type ObjectWithoutKeys<T, K extends keyof T> = ObjectWithKeys<
T,
RemoveFromUnion<keyof T, K>
>;

type Profile = ObjectWithoutKeys<typeof person, “name” | “email”>;
~~~

A

{ age: number; }

This is the same type as a standard utility type called Omit.

261
Q

What is the readonly modifier and what is its syntax?

A

The readonly modifier allows immutable primitive properties to be created. However, this is only compile-time immutability and not runtime immutability.

In the next lesson, we will learn how to create immutable objects and array properties.

type TypeName = {
  readonly propertyName: PropertyType;
};
interface InterfaceName {
  readonly propertyName: PropertyType;
}
class ClassName {
  constructor(public readonly propertyName: PropertyType) {}
}
262
Q

Will Typescript prevent readonly properties to be changed at runtime?

A

No. TypeScript will only raise a type error. It won’t stop readonly properties from actually being updated at runtime. TypeScript doesn’t exist at runtime to prevent such updates.

263
Q

Create a class called Vehicule with 2 properties. name (string) and topspeed a readonly number.

A
class vehicule {
    
    constructor(name:string, readonly topSpeed:number){}
}
264
Q

Is it possible to stop the reference from changing? For example on a property that is a referenced type?

A

Yes. The readonly modifier can be placed before a property that is a reference type (i.e. an object or an array) as follows:
~~~
type TypeName = {
readonly propertyName1: ObjectType;
readonly propertyName2: ArrayType;
};
~~~
This can also be used in interfaces and classes:
~~~
interface InterfaceName {
readonly propertyName1: ObjectType;
readonly propertyName2: ArrayType;
}
class ClassName {
constructor(
public readonly propertyName1: ObjectType,
public readonly propertyName2: ArrayType
) {}
}
~~~
This will stop the property’s reference from changing so that it can’t be changed to another object or array. It, however, doesn’t stop values within the property from changing.

265
Q

Will this prevent the array content from changing ?

readonly propertyName: ArrayType;

A

No. This will stop the property’s reference from changing so that it can’t be changed to another object or array. It, however, doesn’t stop values within the property from changing.
The readonly modifier can be placed before a property that is a reference type (i.e. an object or an array) as follows:

type TypeName = {
  readonly propertyName1: ObjectType;
  readonly propertyName2: ArrayType;
};
This can also be used in interfaces and classes:

interface InterfaceName {
  readonly propertyName1: ObjectType;
  readonly propertyName2: ArrayType;
}
class ClassName {
  constructor(
    public readonly propertyName1: ObjectType,
    public readonly propertyName2: ArrayType
  ) {}
}
266
Q

Explain why no error are raised here:
~~~
interface Result {
name: string;
readonly scores: number[];
readonly profile: {
level: number;
};
}
let billScores: Result = {
name: “Bill”,
scores: [90, 65, 80],
profile: {
level: 1,
},
};

billScores.scores.push(70);
billScores.profile.level = 2;
~~~

A

Putting the readonly keyword before an array property name only ensures its reference won’t change. We can mutate the array, but we can’t set it to a different array. We can put an additional readonly modifier before the array type to ensure the array items aren’t changed:

readonly scores: readonly number[];

Putting the readonly keyword before an object property name only ensures its reference won’t change. We can mutate the profile object, but we can’t set it to a different object. We need to put a readonly modifier before the level property to ensure it isn’t changed:

readonly profile: {
  readonly level: number;
};
267
Q

What is the Readonly utility type?

A

It is a handy utility type that automatically adds the readonly modifier to all the properties in an object type:

type ReadonlyType = Readonly<ExistingType>;</ExistingType>

Note: Readonly only performs a shallow readonly mapping. Readonly also doesn’t add readonly modifiers before array types.

268
Q

What is the syntax to make sure that an object reference AND it’s content can’t be mutated?

A

We need to put an additional readonly modifier before array type to prevent the array items from changing for array types.

For object types, we need to put an additional readonly modifier before properties within the object to prevent them from changing.

readonly propertyName: readonly ArrayType;

type TypeName = {
  readonly propertyName: {
    readonly subPropertyName: PropertyType;
  };
};
269
Q

Is there a way to create immutable objects at both runtime AND compile time?

A

Yes. We need to use Object.freeze

270
Q

Create a let variable assigned to an array of 3 numbers: 90, 65, 80 that will be immutable at both runtime and compile time.

A

let billScores = Object.freeze([90, 65, 80]);

271
Q

What will be the inferred type of:
let billScores = Object.freeze([90, 65, 80]);

A

readonly number[]

272
Q

Will this raise an error at runtime? What will be the error?
~~~
let billScores = Object.freeze([90, 65, 80]);
billScores.push(100);
~~~

A

Yes.
[ERR]: “Executed JavaScript Failed:”
[ERR]: Cannot add property 3, object is not extensible

273
Q

What will be the inferred type here? Will this raise an error at runtime?
let bill = Object.freeze({
name: “Bill”,
age: 30,
});

bill.age = 31;

A

Yes an error will be raised.
The inferred type will be:

Readonly<{
name: string;
age: number;
}>

274
Q

Will this raise a type a runtime error? If not why? If it does why? Will the values be changed?
~~~
let bill = Object.freeze({
name: “Bill”,
age: 30,
scores: [90, 65, 80],
profile: {
level: 1
}
});

bill.scores.push(100);
bill.profile.level = 2;
~~~

A

No type or runtime error. For compile time the Readonly type only creates a type that does a shallow readonly check. At runtime Object.freeze performs only a shallow freeze on an object.

The values are changed.

275
Q

What will be Bill score and why?
~~~
function doubleScores(scores: number[]) {
scores.forEach((score, i) => (scores[i] = score * 2));
return scores;
}

const billScores = [90, 65, 80];

console.log(billScores);
~~~

A

[180, 130, 160]
The function mutate the parameter which is a reference type. This can cause all kind of weird bugs.

276
Q

Make scores readonly here:
~~~
function doubleScores(scores: number[]) {
scores.forEach((score, i) => (scores[i] = score * 2));
return scores;
}
~~~

A
function doubleScores(scores: readonly number[]) {
  scores.forEach((score, i) => (scores[i] = score * 2));
  return scores;
}
277
Q

This will raise an error. What will be the error?
~~~
function doubleScores(scores: readonly number[]) {
scores.forEach((score, i) => (scores[i] = score * 2));
return scores;
}
~~~

A

Mutating the array here is not allowed:
scores[i] = score * 2

278
Q

Correct this function so that it does not mutate the parameter anymore:
~~~
function doubleScores(scores: readonly number[]) {
scores.forEach((score, i) => (scores[i] = score * 2));
return scores;
}
~~~

A
function doubleScores(scores: readonly number[]) {
  return scores.map((score, i) => score * 2);
}
279
Q

Wil the value of score change here?
~~~
type PersonScore = {
name: string;
score: number;
};
function doubleScore(person: PersonScore) {
person.score = person.score * 2;
return person;
}

const bill: PersonScore = {
name: “Bill”,
score: 90,
};
const doubleBill = doubleScore(bill);
console.log(bill, doubleBill);
~~~

A

The function mutates the score property within the parameter. The parameter is a reference type, so updates to it will be visible outside the scope of the function as well as inside it.

280
Q

Make person readonly in the function using the Readonly utility class:
~~~
type PersonScore = {
name: string;
score: number;
};
function doubleScore(person: PersonScore) {
person.score = person.score * 2;
return person;
}

const bill: PersonScore = {
name: “Bill”,
score: 90,
};
const doubleBill = doubleScore(bill);
console.log(bill, doubleBill);
~~~

A
function doubleScore(person: Readonly<PersonScore>) {
  return { ...person, score: person.score * 2 };
}
281
Q

What is a const assertions and what is it used for?

A

A const assertion is a kind of type assertion where the keyword const is used in place of the type:

let variableName = someValue as const;

The const assertion results in TypeScript giving the variable an immutable type based on the value structure. Here are some key points on how TypeScript infers the type from a const assertion:

For objects, all its properties will have the readonly modifier. The readonly modifier is recursively applied to all nested properties.

The readonly modifier is applied to arrays. The type will also be a fixed tuple of specific literal values in the array.

Primitives will be a literal type of the specific value of the primitive.

282
Q

Make bill deeply immutable using a const ```
type asssertion.
const bill = {
name: “Bill”,
profile: {
level: 1,
},
scores: [90, 65, 80],
};
~~~

A

const bill= {
name: “Bill”,
profile: {
level: 1,
},
scores: [90, 65, 80],
} as const ;

283
Q

What will be the type given to bill here:
~~~
const bill= {
name: “Bill”,
profile: {
level: 1,
},
scores: [90, 65, 80],
} as const ;
~~~

A
{
  readonly name: "Bill";
  readonly profile: {
    readonly level: 1;
  };
  readonly scores: readonly [90, 65, 80];
}
284
Q

Will a const type assertion raise error at runtime?

A

The const assertion gives us deep immutability at compile time only.

285
Q

Create a generic function to create a deep immutable type at runtime?

A

We can create a deepFreeze function like this one:
~~~
function deepFreeze<T>(obj: T) {
var propNames = Object.getOwnPropertyNames(obj);
for (let name of propNames) {
let value = (obj as any)[name];
if (value && typeof value === "object") {
deepFreeze(value);
}
}
return Object.freeze(obj);
}
~~~</T>

and use it like this. We add the as const type assertion to also make it compile time immutable.

const bill = deepFreeze({
  name: "Bill",
  profile: {
    level: 1,
  },
  scores: [90, 65, 80],
} as const);
286
Q

Create a generic immutable type called Immutable.

A

type Immutable<T> = {
readonly [K in keyof T]: Immutable<T[K]>;
};</T>

287
Q

Does a type error occur on the assignment on the last line?

type Readings = {
  readonly date: Date;
  readonly values: number[];
}
const readings: Readings = {
  date: new Date(),
  values: [4, 3, 5]
}
readings.values.push(1);
A

No. The items in the array are mutable. A readonly modifier needs to be placed before the type for the array items to be immutable.

288
Q

Do any type errors occur on the surname and rating assignments on the last 2 lines?

type Person = {
  firstName: string;
  surname: string;
  profile: {
    rating: string;
  }
}
const bob: Readonly<Person> = {
  firstName: "Bob",
  surname: "Keel",
  profile: {
    rating: "medium"
  }
};

  bob.surname = "Steel";
  bob.profile.rating = "high";
A

Yes on surname assignment but not on the rating assignment.

The Readonly type creates a shallow immutable type, so a type error will only occur on the surname assignment.

289
Q

What will be output to the console when the transpiled JavaScript is executed?

type Person = {
  firstName: string;
  surname: string;
}
const bob: Readonly<Person> = {
  firstName: "Bob",
  surname: "Keel"
};
bob.surname = "Smith";
console.log(bob.surname);
A

‘Smith’

290
Q

Do any type errors occur on the assignments on the last 2 lines?

const bob = {
  name: {
    firstName: "Bob",
    surname: "Keel"
  },
  profile: {
    rating: "medium"
  }
} as const;

bob.name.surname = "Smith";
bob.profile.rating = "high";
A

Yes on both lines.

291
Q

Do any type errors occur in the function?

type Person = {
  name: string;
  profile: {
    level: number;
  }
};
function increaseLevel(person: Readonly<Person>) {
  person.profile.level++;
  return person;
}
A

No. The Readonly type creates a shallow immutable type, so changing the level property won’t raise a type error.

292
Q

What will be output to the console when the transpiled JavaScript is executed? Is a type error raised?
~~~
type Person = {
firstName: string;
surname: string;
}
const bob: Readonly<Person> = Object.freeze({
firstName: "Bob",
surname: "Keel"
});
bob.surname = "Smith";
console.log(bob.surname);
~~~</Person>

A

Yes a type error is raised at compile time. Cannot assign to ‘surname’ because it is a read-only property.(2540)

293
Q

In Typescript strict mode will this generate an error? If so what error?
~~~
class Product {
name: string;
price: number;
}
~~~

A

The fields have been defined as required fields, but the class can be instantiated with these fields being undefined.

In TypeScript, if strict mode is on, fields must be given an initial value or be optional