The Basics Flashcards

1
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
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>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
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}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
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>;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
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.

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

What is ReturnType

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
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) {}
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
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){}
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
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.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
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
  ) {}
}
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
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;
};
19
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.

20
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;
  };
};
21
Q

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

A

Yes. We need to use Object.freeze

22
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]);

23
Q

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

A

readonly number[]

24
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

25
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;
}>

26
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.

27
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.

28
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;
}
29
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

30
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);
}
31
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.

32
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 };
}
33
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.

34
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 ;

35
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];
}
36
Q

Will a const type assertion raise error at runtime?

A

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

37
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);
38
Q

Create a generic immutable type called Immutable.

A

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

39
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.

40
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.

41
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’

42
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.

43
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.

44
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)