The Basics Flashcards

1
Q

What is type narrowing?

A

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

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

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

A

Element | null

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

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

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

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

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

A

The as syntax is preferred

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

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

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

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

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

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

Using instanceof How would you add the missing todo knowing that Person and Organisation extend Contact?

class Contact {
  constructor(public emailAddress: string) {}
}
class Person extends Contact {
  constructor(
    public firstName: string,
    public surname: string,
    emailAddress: string
  ) {
    super(emailAddress);
  }
}
class Organisation extends Contact {
  constructor(public name: string, emailAddress: string) {
    super(emailAddress);
  }
}

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

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

interface Person {
  firstName: string;
  surname: string;
}
interface Organisation {
  name: string;
}
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.

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

17
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 and call the function isPerson.
Perform the check on firstName.

A

The first solution is favored and less error prone:

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

But this also works:

function isPerson(contact:Contact): contact is Person
{
    return 'firstName' in contact;
}
18
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.

19
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 assertIsPerson 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.

20
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: "value2"
}
...
type TypeN = {
  ...
  commonName: "valueN"
}
  1. 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
  2. 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;
  }
}
21
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.

22
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

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

24
Q

Create a user-defined type guard with the following:

isTypeName
paramName
WideTypeName
NarrowTypeName

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.

25
Q

Create an assertion signature using these:

assertTypeName
paramName
WideTypeName
paramName
NarrowTypeName

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.
How well did you know this?