---
# System prepended metadata

title: Working with types - Natalia

---

# Working with types - Natalia

## 1.4 How to check if a string is part of an Enum?

### Using `in` operator to check if the key string is part of an Enum
```typescript
enum BreakingBadCharacters {
  WalterWhite = "Heisenberg",
  JessePinkman = "Cap'n Cook",
  SaulGoodman = "Slippin' Jimmy",
}

const isCharacterInBreakingBad = (character: string): boolean => {
  return character in BreakingBadCharacters;
};

console.log(isCharacterInBreakingBad("WalterWhite")); // true
console.log(isCharacterInBreakingBad("GusFring")); // false
```

### Using `Object.values()` to check if the value string is part of an Enum

```typescript
enum BreakingBadNicknames {
  Heisenberg = "Walter White",
  CapnCook = "Jesse Pinkman",
  SlippinJimmy = "Saul Goodman",
}

const isNicknameFromBreakingBad = (nickname: string): boolean => {
  // let nicknames = Object.values(BreakingBadNicknames);
  let nicknames: string[] = Object.values(BreakingBadNicknames) as string[];
  return nicknames.includes(nickname);
};

console.log(isNicknameFromBreakingBad("Walter White")); // true
console.log(isNicknameFromBreakingBad("Mike")); // false
```

### Using `Object.values()` to check if both the key or value string is part of an Enum
```typescript
enum BreakingBadElements {
  Methamphetamine = "Blue Crystal",
  HydrofluoricAcid = "Dissolve",
  Chromium = "Cr",
}

const isElementOrCompoundInBreakingBad = (input: string): boolean => {
  const keys = Object.keys(BreakingBadElements) as string[];
  const values = Object.values(BreakingBadElements) as string[];
  return keys.includes(input) || values.includes(input);
};

console.log(isElementOrCompoundInBreakingBad("Methamphetamine")); // true (key)
console.log(isElementOrCompoundInBreakingBad("Blue Crystal")); // true (value)
console.log(isElementOrCompoundInBreakingBad("Pizza")); // false
```








## 1.5. How to make only some properties of an interface mandatory?
https://plainenglish.io/blog/how-to-make-certain-properties-optional-in-typescript-9b4f8e85c5de
I feel like the way this blog develop the problem is really good. So I'll replicate those step here.

```typescript
interface SpellCaster {
  name: string;
  surname: string;
  house: string;
  age: number; //Normal way to make a field mandatory
  pet?: Animal; //Normal way to make a field optional is using `?`
}

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

//Assume we want to create a function to return the fullname
const spellCasterFullName = ({ surname, name }: SpellCaster): string => {
  return `${name} ${surname}`;
};

const spellCaster1: SpellCaster = {
  name: "Harry",
  surname: "Potter",
  house: "Gryffindor",
  age: 17,
};

console.log(spellCasterFullName(spellCaster1.surname, spellCaster1.name));
```

this works well, but now when you want to call the function spellCasterFullName else where, you would need to create a new SpellCaster
`console.log(spellCasterFullName({ surname: "Granger", name: "Herminone" }));`
this `{surname:"Granger", name: "Herminone"}` doesn't match SpellCaster type

Then, it's where Partial<T> come to play:

```typescript
function spellCasterFullName({ name, surname }: Partial<SpellCaster>): string {
  return `${name} ${surname}`;
}
console.log(spellCasterFullName({ surname: "Granger", name: "Herminone" }));
```

But then, `{surname:string, name: string}` become `{surname:string|undefined, name: string|undefined}` so we need to perfom some type check like

we want name and surname mandatory and match with the type that define in the interface SpellCaster
=> we can use `Pick<T, Keys>` which selects some properties Keys from the T.

```typescript
const spellCasterFullName = ({
  name,
  surname,
}: Pick<SpellCaster, "name" | "surname">): string => {
  return `${name} ${surname}`;
};

console.log(spellCasterFullName(spellCaster1));
console.log(spellCasterFullName({ surname: "Granger", name: "Herminone" }));
```

### A step further, in the case that we want to return characteristic of that person based on their house. it can be achieved by

```typescript
const getCharacteristic = (house: string): string => {
  return "brave"; //let assume that all house characteristic return bravery, but we know that this value might differ from houses
};

const spellCasterFullName = ({ name, surname, house }: SpellCaster): string => {
  if (house) {
    const characteristic = getCharacteristic(house);
    return `${name} ${surname} is ${characteristic}`;
  }

  return `${name} ${surname}`;
};
console.log(spellCasterFullName(spellCaster1));
```

but we don't need all SpellCaster properties just to return short name where there is no house
then here is a solution

```typescript
const spellCasterFullName = (
  sp: Partial<SpellCaster> & Pick<SpellCaster, "name" | "surname">,
): string => {
  const { name, surname, house } = sp;
  if (house) {
    const characteristic = getCharacteristic(house);
    return `${name} ${surname} is ${characteristic}`;
  }

  return `${name} ${surname}`;
};
console.log(spellCasterFullName(spellCaster1));
console.log(spellCasterFullName({ surname: "Granger", name: "Herminone" }));
```
    
## 1.6 How to assign properties to an object dynamically?
    

```typescript
//wrong way:
const character = {}
character.name = "Severus Snape";

//or
const character = {
  name = "Severus Snape";
}
character.age = 20

```

### 1. Declaring the Object with Explicit Type
This method is used when the shape of your object is known and unlikely to change
```typescript
const character: { name: string } = {};
character.name = "Severus Snape";
console.log("After dynamic assignment: ", character.name);
```
    
### 2. Using the Index Signature of the Object
    
Flexible object that can have any number of properties of a certain type
    
```typescript
const magicalCreature: { [name: string]: any } = {};

// Dynamically adding more properties
magicalCreature.species = "Snowy Owl";
magicalCreature.owner = "Harry Potter";
console.log(`Updated creature: ${magicalCreature.name}, a ${magicalCreature.species}, owned by ${magicalCreature.owner}`);
//not even need to define the name property

```
    
### 3. Using the Record Utility Type
    
```typescript
const houseColors: Record<string, string[]> = {
  Gryffindor: ["Scarlet", "Gold"],
};
console.log("Before dynamic assignment: ", houseColors.Gryffindor);

// Dynamically adding more houses and their colors
houseColors.Hufflepuff = ["Yellow", "Black"];
houseColors.Ravenclaw = ["Blue", "Bronze"];
houseColors.Slytherin = ["Green", "Silver"];

console.log("After dynamic assignment: ");
for (const house in houseColors) {
  console.log(`${house}: ${houseColors[house].join(" and ")}`);
}
```
    
## 1.7 How to exclude properties readonly from a type
    
Original Character Type
```typescript
type Wizard = {
    readonly id: number;
    readonly name: string;
    house: string;
};
```
    
### 1. Making All Properties Mutable
```typescript
type RemoveReadonlyForAll<T> = {
    -readonly [P in keyof T]: T[P];
};

type EditableWizard = RemoveReadonlyForAll<Wizard>;

const editableWizard: EditableWizard = {
    id: 1,
    name: "Harry Potter",
    house: "Gryffindor"
};

// Demonstrating mutability
editableWizard.id = 2; // Success
editableWizard.name = "Harry James Potter"; // Success
editableWizard.house = "Slytherin"; // Success
```

### 2. Removing readonly from Specific Properties
```typescript
type RemoveReadonly<T, K extends keyof T> = {
      -readonly [P in K]: T[P];
  } & {
      [P in Exclude<keyof T, K>]: T[P];
  };

// Making only the 'name' property mutable
type NameChangeableWizard = RemoveReadonly<Wizard, 'name'>;
    
const nameChangeableWizard: NameChangeableWizard = {
    id: 3,
    name: "Hermione Granger",
    house: "Gryffindor"
};

// Trying to mutate
// nameChangeableWizard.id = 4; // Error: Cannot assign to 'id' because it is a read-only property.
nameChangeableWizard.name = "Luna Lovegood"; // Success
// nameChangeableWizard.house = "Ravenclaw"; // This would still work as 'house' was mutable from the start.
```
    
### 3. Manually Adjusting Properties
```typescript
// Exclude 'id' and 'name' from Wizard, then add them back as mutable
type IdentityChangedWizard = Omit<Wizard, 'id' | 'name'> & {
    id: number;
    name: string;
};
    
    
const identityChangedWizard: IdentityChangedWizard = {
    id: 5,
    name: "Ron Weasley",
    house: "Gryffindor"
};

// Demonstrating allowed changes
identityChangedWizard.id = 6; // Success
identityChangedWizard.name = "Ronald Bilius Weasley"; // Success
// identityChangedWizard.house = "Hufflepuff"; // This would still work as 'house' was mutable from the start.
```
    
## 1.8 How to extract a type from a interface property?
    
```typescript
interface MagicalBook {
  title: string;
  author: string;
  magicalProperties: any;
}

interface HogwartsCurriculum {
  potions: {
    textbook: MagicalBook,
    supplementary: MagicalBook[]
  };
  defenseAgainstTheDarkArts: {
    textbook: MagicalBook,
    supplementary: MagicalBook[]
  };
  // Additional classes can be added here
}
```
    
### Extract the specific structure using indexed access type
```typescript
// Extracting the type for supplymentary book of potion class
type PotionClassSupplymentaryBook = HogwartsCurriculum["potions"]["supplymentary"]
//PotionClassSupplymentaryBook = MagicalBook[]
    
    
// Extracting the type for Potions class reading materials

type PotionsReadingMaterials = HogwartsCurriculum["potions"];
// PotionsReadingMaterials = {
//    textbook: MagicalBook,
//    supplementary: MagicalBook[]
//  }
```
Question: why using `type PotionClassSupplymentaryBook = HogwartsCurriculum["potions"]["supplymentary"]
//PotionClassSupplymentaryBoo` but not `type PotionClassSupplymentaryBook = MagicalBook[]`?
    
In a scenario where the *structure of MagicalBook changes, or the potions class structure is updated to include a new category of books*. If you had used `MagicalBook[]` directly, these changes would not be reflected in the `PotionClassSupplementaryBook` type without manual intervention. However, by using `HogwartsCurriculum["potions"]["supplementary"]`, your type definitions remain accurate and **up-to-date** with minimal effort.
    
### Utilizing keyof to Enumerate Hogwarts Classes
```typescript
type HogwartsClass = keyof HogwartsCurriculum;
    
//HogwartsClass = "potions" | "defenseAgainstTheDarkArts"
```
    
- Example Usage
We can use this HogwartsClass type to ensure that functions dealing with classes only accept valid class names.

```typescript
function listMaterialsForClass(className: HogwartsClass) {
  // Implementation: list all materials for the given class
}
```
    
## 1.9 How to restrict a number to a certain range
    
```typescript
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
  ? Acc[number]
  : Enumerate<N, [...Acc, Acc['length']]>;

type Range<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;

type T = Range<3,5>;

```
    
### Goal
We want to create a type that represents a sequence of numbers from the range 3-5 . This sequence is a range of numbers from 3 (inclusive) to 5 (exclusive).

### Enumerate Type

First, we have a helper type called Enumerate. This generates a sequence of numbers starting from 0 up to (but not including) a number N you specify. 

```typescript
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
  ? Acc[number]
  : Enumerate<N, [...Acc, Acc['length']]>
    
//Enumerate<3> 
//=> This would generate a union from 0 to 2: 0|1|2
```
    
Here's how it works:

- It takes a number N and starts with an empty list (or array) called Acc (short for "Accumulator").
- It looks at the length of `Acc`. If the length matches N, it stops and gives us a list of numbers from 0 up to N-1.
- If the length of Acc is not yet N, it adds the current length of Acc to the end of Acc and tries again. This step is repeated until Acc contains N numbers.
    
#### Dry Run Example: Enumerate<3>
Let's see how this works step by step to generate a sequence [0, 1, 2].
```typescript
    
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
  ? Acc[number]
  : Enumerate<N, [...Acc, Acc['length']]>

//Initial Call: 
    Enumerate<3>

//Step 1: Start with an empty Acc
//Enumerate<3>
    Acc = []
    Acc.length = 0 //(Does not match N=3)
//=> Acc['length'] extends 3 return false
//=> call Enumerate<N, [...Acc, Acc['length']]> 
// that now is 
    Enumerate<3, [0]>

//Step 2: Add Acc.length to Acc and recurse
//Enumerate<3, [0]>
    New Acc = [0]
    Acc.length = 1 //(Does not match N=3)
//Recursive Call 
    Enumerate<3, [0,1]>

//Step 3: Add Acc.length to Acc and recurse
//Enumerate<3, [0,1]>
    New Acc = [0,1]
    Acc.length = 2 //(Does not match N=3)
//Recursive Call Enumerate<3, [0,1,2]>
    
//Step 4: Add Acc.length to Acc and recurse
//Enumerate<3, [0,1,2]>
    New Acc = [0,1,2]
    Acc.length = 3 //(match N=3)
//=> Acc['length'] extends 3 return true 
//so we stop here and return Acc["number"] 

    
```


Final Result
The process stops because Acc.length now matches N.
The resulting type from `Acc[number]` is `0 | 1 | 2`, representing each number in the sequence as a union of literals.
    
### Range Type
    
```typescript
type Range<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;
```
    
How It Works:

- `Exclude<Enumerate<T>, Enumerate<F>>`: This uses TypeScript's `Exclude` utility type to subtract the numbers from `0` to `F-1` (generated by `Enumerate<F>`) from the numbers `0` to `T-1` (generated by `Enumerate<T>`). The result is a type that represents each number between `F` and `T-1` as a literal.
    
Example:
```typescript
type T = Range<3, 5>;
```
this equal to
```typescript
Exclude<Enumerate<5>, Enumerate<3>>    
```    
`Enumerate<5>` generates a union type `0 | 1 | 2 | 3 | 4`. 
`Enumerate<3>` generates a union type `0 | 1 | 2`. 

=> `Exclude< 0|1|2|3|4 , 0|1|2> `

=> result in new union type: `3 | 4`
=> `type T = 3 | 4`
    
### Conclusion
```typescript
type Enumerate<N extends number, Acc extends number[] = []> = Acc['length'] extends N
  ? Acc[number]
  : Enumerate<N, [...Acc, Acc['length']]>;

type Range<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>>;

type T = Range<3,5>; 
//=> type T = 3 | 4

```

## 1.10 How to Check if an Object Implements a Type or Interface?
**By using "User Defined Type Guard"**    

Imagine we're at Hogwarts, and we need to verify if a particular magical device, let's call it a `SpellChecker`, implements the `ISpell` interface. This interface ensures that every magical device can cast a spell (castSpell) and has a spell name (spellName).
    
First, we define the ISpell interface
```typescript
interface ISpell {
  spellName: string;
  castSpell: () => void;
}
```
To check if a magical device is truly capable of casting spells as per the ISpell interface, we conjure a **"User Defined Type Guard"** function.

```typescript
const implementsISpell = (object: any): object is ISpell =>{
  return object &&
         typeof object.spellName === 'string' &&
         typeof object.castSpell === 'function';
}
```

We now have a magical device that claims to be capable of checking spells:

```typescript
const spellChecker = {
  spellName: "Lumos",
  castSpell: () => console.log("Let there be light"),
};
    
//Implement type checking at run time
if (implementsISpell(spellChecker)) {
  console.log("spellChecker implements ISpell");
} else {
  console.log("spellChecker does not implement ISpell");
}
```

### Pros and Cons
**Pros**
- Type Safety: This method ensures that objects adhere to specific structures at runtime, offering a layer of type safety beyond compile-time checks.
- Flexibility: Type guards can be customized to check for various properties and methods, providing flexibility in validation logic.

**Cons**
- Manual Checks: For objects with many properties, writing and updating type guards can become cumbersome.
- Runtime Overhead: These checks occur at runtime, potentially impacting performance if used excessively.

### Use Cases
- Input Validation: Ensuring that dynamic content, such as user input or API responses, matches expected types and structures.
- Interoperability: Verifying that objects from external libraries or modules meet the required interfaces for integration.
- Debugging: Aiding in debugging by catching type-related errors at runtime, providing an additional layer of error checking.
    
## 1.11 Keeping the relation key-value using Objects.entries
Define a WizardInventory type
```typescript
type WizardInventory = {
    wand: number,
    potionName: string
};
```
    
The `KeyValuePairs` mapped type transforms an object type into an array of `[key, value]` tuples, keeping the association between each key and its corresponding value type.
    
```typescript
type KeyValuePairs<T> = {
    [P in keyof T]: [P, T[P]];
}[keyof T][];
```
    
**Applying KeyValuePairs to WizardInventory**

```typescript
KeyValuePairs<WizardInventory>
```
When we apply `KeyValuePairs<T>` to `WizardInventory`, here's how TypeScript processes the type:

**1. Iterating Over Keys with `[P in keyof T]`**
```typescript
keyof WizardInventory //result in type "wand" | "potionName"

//the mapped type [P in keyof T] iterates over each of these keys
[P in keyof T] //loop over "wand" and "potitionName"
```

**2. Creating Tuples with [P, T[P]]**

On each iteration, TypeScript creates a tuple [P, T[P]]:
- For `P = "wand"`, `T[P]` is number. 
    - The tuple becomes `["wand", number]`.
- For `P = "potionName"`, `T[P]` is string. 
    - The tuple becomes `["potionName", string]`.
    - At this point, we have a mapped type where each key from WizardInventory is mapped to a tuple of the key name and its type:
```typescript
{
    wand: ["wand", number],
    potionName: ["potionName", string]
}
```
**3. Converting to a Union of Tuples with [keyof T][]**

Applying [keyof T] on this mapped type, which extracts the types of each property into a union. Result in:
```typescript
["wand", number] | ["potionName", string]
```

Finally, adding [] at the end constructs an array type from this union:
```typescript
(["wand", number] | ["potionName", string])[]
```

Final result:
```typescript
type WizardInventory = {
    wand: number,
    potionName: string
};
    
type KeyValuePairs<T> = {
    [P in keyof T]: [P, T[P]];
}[keyof T][];

type InventoryEntries = KeyValuePairs<WizardInventory>;
// Type is (["wand", number] | ["potionName", string])[]
```
    
other example:
```typescript
type KeyValuePairs<T> = {
    [P in keyof T]: [P, T[P]];
}[keyof T][];
    
//Example 1:
type EventHandlers = {
  onClick: () => void;
  onMouseEnter: () => void;
  onKeyPress: (key: string) => boolean;
};

type HandlerEntries = KeyValuePairs<EventHandlers>;
//type is ["onClick", () => void] | ["onMouseEnter", () => void] | ["onKeyPress", (key: string) => boolean])[]
    
    
type MixedTypesObject = {
    id: number;
    isValid: boolean;
    name: string;
    computeScore: (values: number[]) => number;
};

type MixedEntries = KeyValuePairs<MixedTypesObject>;
// Type is [("id", number) | ("isValid", boolean) | ("name", string) | ("computeScore", (values: number[]) => number)][]

```