Type Manipulation Flashcards

1
Q

What does the keyof type operator do?

A

In TypeScript, the keyof type operator is used to create a new type based on the keys (property names) of an existing type. It is often used in the context of creating more generic or reusable types, providing a way to extract the keys of an object and use them as a union type.

Here’s a simple example:

interface Person {
  name: string;
  age: number;
}

type PersonKeys = keyof Person; // "name" | "age"
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

What does the typeof type operator do?

A

In TypeScript, the typeof type operator is used to obtain the type of a value, variable, or expression. When used within a type context, it allows you to create new types based on the inferred type of an existing value or expression. This can be useful in cases where you want to create a type that matches the structure of an object, without having to explicitly define the object’s structure as a separate interface or type alias.

Here’s an example of how to use the typeof type operator in TypeScript:

const exampleObject = {
  id: 1,
  name: "John Doe",
  email: "john.doe@example.com"
};

type ExampleObjectType = typeof exampleObject;

function logDetails(obj: ExampleObjectType) {
  console.log(`ID: ${obj.id}, Name: ${obj.name}, Email: ${obj.email}`);
}

logDetails(exampleObject); // This will work
logDetails({ id: 2, name: "Jane Doe", email: "jane.doe@example.com" }); // This will also work

logDetails({ id: 3, name: "Invalid", missingEmail: "missing@example.com" }); // This will cause a TypeScript error
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Given this function

function f() {
  return { x: 10, y: 3 };
}

Create a type P that represents the return type fo the f function.

A
type P = ReturnType<typeof f>;
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

What are the limitations of the typeof type operator?

A

TypeScript intentionally limits the sorts of expressions you can use typeof on.

Specifically, it’s only legal to use typeof on identifiers (i.e. variable names) or their properties. This helps avoid the confusing trap of writing code you think is executing, but isn’t:

// Meant to use = ReturnType<typeof msgbox>
let shouldContinue: typeof msgbox("Are you sure you want to continue?"); // Error: ',' expected.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

What do indexed access types do?

A

In TypeScript, indexed access types, also known as lookup types, allow you to access the type of a property of another type using a key.

This can be useful when you want to create a new type that’s based on a specific property of another type, or when you want to access a nested property’s type. Indexed access types use the syntax T[K], where T is the type you want to access and K is the key (property name) whose type you want to obtain.

Here’s an example of how to use indexed access types:

interface Person {
  id: number;
  name: string;
  email: string;
}

type PersonName = Person["name"]; // PersonName is of type string
type PersonEmail = Person["email"]; // PersonEmail is of type string
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Can you use indexed access types with generics?

A

Yes, you can.

For example:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const person: Person = {
  id: 1,
  name: "John Doe",
  email: "john.doe@example.com"
};

const personName = getProperty(person, "name"); // personName is inferred as string
const personEmail = getProperty(person, "email"); // personEmail is inferred as string

In this example, we define a generic getProperty function that takes an object of type T and a key of type K, where K is a key of T. The function returns a value of type T[K]. This allows us to use the getProperty function to access properties of various types and get the correct return type based on the input type and key.

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

What does the satisfies operator do?

A

The satisfies operator checks if a given type satisfies a specific condition or interface.

For example Let’s create a type called personInfo, which is a union of personName and otherDetails.

type personName = "John" | "Jack" | "Justin";
type otherDetails = {
  id: number;
  age: number;
};
type personInfo = personName | otherDetails;

Now let’s create the Person type.

type Person = {
  myInfo: personInfo;
  myOtherInfo: personInfo;
};

The Person type has two properties, myInfo and myOtherInfo, both of which will be of type personInfo. This indicates that both properties can either be personName or otherDetails. Now, let’s create the variable applicant.

const applicant: Person = {
  myInfo: "John",
  myOtherInfo: { id: 123, age: 22 },
};

Now, let’s imagine we want to access myInfo and convert it to uppercase.

applicant.myInfo.toUpperCase(); // Error: Property 'toUpperCase' does not exist on type 'personInfo' and Property 'toUpperCase' does not exist on type 'otherDetails'

This error occurs because TypeScript is unsure whether the value of myInfo or myOtherInfo is a string or an object since we have defined our personInfo as a union of string and object.

In order to remove this error, we have to manually validate the property as shown below:

if (typeof applicant.myInfo === "string") {
  applicant.myInfo.toUpperCase();
}

Now, with the help of the satisfies operator, you don’t need to do all this.

const applicant = {
  myInfo: "John",
  myOtherInfo: { id: 123, age: 22 },
} satisfies Person;

applicant.myInfo.toUpperCase(); // no error

The satisfies operator determines that the myInfo variable is a string and not an object. This is because, before executing the code, it checks all the values of the Person type. This operator ensures that we assign any value that satisfies the Person type to the applicant variable.

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