🤯 Typescript features you may not know
Tags: typescript
Published: 2020-02-20 09:14:57

TypeScript- the love child of C# and JavaScript which you should be proud of and show off to your family.

## Topics
🔑 [keyof](#keyof)
🔏 [Access Modifiers](#access-modifiers)
⚡ [static](#static)
🚔 [Type Guards (User-defined)](#type-guards)
💔 [Partial](#partial)
⛏  [Pick & Omit](#pick-omit)

### 🔑 <a name="keyof"></a> keyof


This one does what it says on the tin.  It gets the keys of an interface, type or object.


```typescript

interface MyType {
  id: number;
  category: number;
  name: string;
}

function getProperty<T>(item: T, key: keyof T) {
  // more code goes here
}

// const item: MyType = { ... }

getProperty(item, 'id') // Valid
getProperty(item, 'other') // Error

```

### 🔏 <a name="access-modifiers"></a> Access Modifiers

Access modifiers allow us to close down (or open up) access to properties on a class.

**private**: Only accessible within the class it was defined in.
**protected**: Accessible within the class it was defined in & any classes inheriting from it.
**public**: Accessible from anywhere.

```typescript
class BaseClass {
  private privateProperty: string;
  protected protectedProperty: string;
  public publicProperty: string; // default is public, can be omitted

  constructor(
    privateProperty: string,
    protectedProperty: string,
    publicProperty: string
  ) {
    this.privateProperty = privateProperty;
    this.protectedProperty = protectedProperty;
    this.publicProperty = publicProperty;
  }

  baseMethod() {
    console.log(this.privateProperty); // Valid
    console.log(this.protectedProperty); // Valid
    console.log(this.publicProperty); // Valid
  }
}

class ParentClass extends BaseClass {
  methodA() {
    console.log(this.privateProperty); // Invalid
    console.log(this.protectedProperty); // Valid
    console.log(this.publicProperty); // Valid
  }
}

let item = new ParentClass("private", "protected", "public");
console.log(item.privateProperty); // Invalid
console.log(item.protectedProperty); // Invalid
console.log(item.publicProperty); // Valid
```

**Note** JavaScript doesn't have the concept of access modifiers as we know them ([yet](https://github.com/tc39/proposal-class-fields/)!), so it's only enforced in TypeScript land.  Once it hits JavaScript land it's public all the way. 

### ⚡ <a name="static"></a> Static
With static we can add properties to a class and access it without the need to create an instance of the class.

```typescript
class MyClass {
  static value = 13.31;
  value = 89.98;

  process(num: number) {
    return num * MyClass.value;
  }
}

console.log(MyClass.value) // 13.31

// const myClassInstance = new MyClass();
// console.log(myClassInstance.value); // 89.98 (using the instance value and not the static value)
```

### 🚔 <a name="type-guards"></a> Type Guards (User-defined)
Have you ever written a function that accepts a union type and then experienced trouble when trying to handle the different types, look no further!  Type Guards allow us to define a function that will perform a runtime check that will assure you of a single type within some scope.

Some of you may think that `typeof` is the solution, but sadly this only works for primitive types. 

```typescript
type MyTypeA = {
  typeAProp: number;
  otherAProp: string;
  sameProp: boolean;
};

type MyTypeB = {
  typeBProp: number;
  otherBProp: string;
  sameProp: boolean;
};

function myFunc(item: MyTypeA | MyTypeB) {
  if (isMyTypeA(item)) {
    console.log(item.typeAProp, item.otherAProp, item.sameProp) // valid
  }

  // item.typeAProp // invalid
  // item.sameProp // valid
  ...
}

function isMyTypeA(item: MyTypeA | MyTypeB): item is MyTypeA {
  // Return a condition, that guarantees your type is what you are after
  return (item as MyTypeA).typeAProp !== undefined;
}
```

### 💔 <a name="partial"></a> Partial
Partial will set all properties (except nested properties, we'll touch on this in a bit) as optional.

```typescript
type MyType = {
  RequiredProp1: string;
  RequiredProp2: number;
  OptionalProp1?: boolean;
}

type PartialMyType = Partial<MyType>;

// This will produce an error, as RequiredProp1 is missing
const item: MyType = {
  RequiredProp2: 42
}


// This is valid, as partial marked everything as optional
const partialItem: PartialMyType = {
  RequiredProp2: 42
}
```

As you can see from the example above, `Partial` saves us from having to define a nearly duplicate type and marking everything as optional ourselves.

**Note** there is a built in utility method that does the opposite of `Partial` called `Required`.  Its usage is identical to the above.

**Bonus** To apply partial to your nested types recursively, use the following snippet

```typescript
type RecursivePartial<T> = { [P in keyof T]?: RecursivePartial<T[P]> };

// Usage
type EverythingPartial = RecursivePartial<MyType>;
```

### ⛏ <a name="pick-omit"></a> Pick & Omit
Pick & Omit are useful when it comes to creating a sub type from an external (or internal) interface or types.


```typescript
// external.ts
interface ExternalInterface {
  name: string;
  address: string;
  age: number;
}

// mycode.ts

// Pick
type MyPickType = Pick<ExternalInterface, 'name' | 'age'>;


// Omit
type MyOmitType = Omit<ExternalInterface, 'address'>;

```

Both `MyPickType` and `MyOmitType` end up consisting of the same properties.  As the term `Pick` suggests, you pick which properties you want on your new type.  With `Omit` you exclude the properties you list.

## Footnote

If I left out a hidden gem or if you need clarification on anything, let me know!

Proof read & edited by my beautiful wife ❤!

Remember to #KeepHavingFun