Functional programming with Angular. 2. Typechecking
Published: 2021-05-22 15:48:40

Typechecking is what typescript does for us. Unfortunately, it's not always true in core part of Angular world - templates.

In previous part we completed initial approach with Either type, representing union of Data (Right) and Error (Left). Now we will look in more details how this type is handled in [@sweet-monads/either](https://github.com/JSMonk/sweet-monads/tree/master/either).

**Either#mapRight**
```typescript
function mapRight<L, R, NewR>(fn: (val: R) => NewR): Either<L, NewR>;
```

> Returns mapped by fn function value wrapped by Either if Either is Right otherwise Left with L value

*Example*:
```typescript
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());

const newVal1 = v1.map(a => a.toString()); // Either<Error, string>.Right with value "2"
const newVal2 = v2.map(a => a.toString()); // Either<Error, string>.Left with value new Error()
```

**Either#mapLeft**
```typescript
function mapLeft<L, R, NewL>(fn: (val: L) => NewL): Either<NewL, R>;
```
> Returns mapped by fn function value wrapped by Either if Either is Left otherwise Right with R value

*Example*:
```typescript
const v1 = right<Error, number>(2);
const v2 = left<Error, number>(new Error());

const newVal1 = v1.mapLeft(a => a.toString()); // Either<string, number>.Right with value 2
const newVal2 = v2.mapLeft(a => a.toString()); // Either<string, number>.Left with value "Error"
```

So we might update first naive implementation from previous part with this code

![either typescript](https://i.ibb.co/MD841Ny/typechecking-either-naive.png)

But its not required as we used pure Either in template. How? Look into directive in previous part
```typescript
@Directive({ selector: '[fpIfRight]' })
export class IfRightDirective<TE = unknown, TD = unknown> {
  static ngTemplateGuard_fpIfRight: 'binding'; // * Static binding

  private _context: IfContext<TE | TD> = initialIfContext(); // *  Initialization
  private _refs = initialRefs();

  constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef<IfContext<TE | TD>>) {
    this._refs.viewContainer = viewContainer;
    this._refs.thenTemplateRef = templateRef;
  }

// * Directive's Input
  @Input()
  set fpIfRight(either: Either<TE, TD> | null) {
    if (either) {
      either
        .mapLeft(l => {
          this._context.ifTrue = false;
          this._context.$implicit = l;
        })
        .mapRight(r => {
          this._context.ifTrue = true;
          this._context.$implicit = r;
        });
    }
    updateView(this._context, this._refs);
  }

  @Input()
  set fpIfRightThen(templateRef: TemplateRef<IfContext<TE | TD>> | null) {
    this._refs.thenTemplateRef = templateRef;
    this._refs.thenViewRef = null;
    updateView(this._context, this._refs);
  }

// * Handling ELSE block in template
  @Input()
  set fpIfRightElse(templateRef: TemplateRef<IfContext<TE | TD>> | null) {
    this._refs.elseTemplateRef = templateRef;
    this._refs.elseViewRef = null;
    updateView(this._context, this._refs);
  }

// * Context validation magic
  static ngTemplateContextGuard<TE, TD>(
    _dir: IfRightDirective<TE, TD>,
    _ctx: any
  ): _ctx is IfContext<Exclude<TD, false | 0 | '' | null | undefined>> {
    return true;
  }
}

```

Lets start from the usage of directive

![usage in html](https://i.ibb.co/ncS782t/typechecking-eeither-html.png)

Here we declaring structural directive with if block, adding ELSE block for Left case (*errorTpl*) and specify variable with implicit context (*let ok*). This *ok* variable will have correct type even in VSCode syntax with Angular language service, just be sure that you specify [strict](https://angular.io/guide/template-typecheck#strict-mode)  in compiler options. It's available due to some code in our directive, see it later in topic.

*  Initialization
Here we initializing default values for our template, should it be in empty state or not. The same as with ngIf implementation, yes, it's kind of empty until first value arrives.

* Directive's Input
Thats the place where we getting value from this line
```html
<ng-container *fpIfRight="stations; else errorTpl; let ok">
```

* Handling ELSE block in template
This block will be used when we will be handling Left state of our Either container. Unfortunately, it still [not available for typecheck](https://github.com/angular/angular/issues/28731).

* Static binding
Thats part related to Ivy- we specifying that we will build template from our code

* Context validation magic
That's part I mostly like with Ivy. With [Ivy magic](https://angular.io/guide/structural-directives#improving-template-type-checking-for-custom-directives) we can declare for compiler what type supposed be used by structural directive.


All this typechecking gives us a lot of power for structural directives and custom templates. 

{% github https://github.com/Lonli-Lokli/functional_angular %}