Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Need help in understanding confusing Typescript function

I've come across the following code which is a filter callback function on an array. I'm confused trying to understand what this function is doing and am trying to break it down into smaller bits to understand but I can't seem to get my head around it.

I'm trying to learn TypeScript and know some JS but the syntax is confusing for me.

Could someone please explain how this function would operate on an arrays inputs please? a sort of walk through of the syntax in this exampled would be helpful. Thanks.

const check = (Boolean as any) as <T>(
  a: T | false | undefined | null | ''
) => a is T;
like image 862
j obe Avatar asked Dec 23 '20 18:12

j obe


People also ask

How do you pass a function in TypeScript?

Similar to JavaScript, to pass a function as a parameter in TypeScript, define a function expecting a parameter that will receive the callback function, then trigger the callback function inside the parent function.

How do you call a function with parameters in TypeScript?

In functions, parameters are the values or arguments that passed to a function. The TypeScript, compiler accepts the same number and type of arguments as defined in the function signature. If the compiler does not match the same parameter as in the function signature, then it will give the compilation error.

Can JavaScript call TypeScript function?

TypeScript supports the existing JavaScript function syntax for declaring and calling it within the program or the code snippet.


1 Answers

Ok, this function is kinda... crazy. Let's breakdown this code a bit.

First, take the following idiom as an example:

const something = ('' as any) as boolean
// something's type is boolean for Typescript, but its value is actually a string!

the (X as any) as Y idiom is a hack that allows you to tell typescript that something is actually something else. You're taking full control of the type system, and Typescript won't be able to infer the underlying value - and much less catch it. It can lead to bugs, such as the above example where I tell TS that an empty string is a boolean.

Now, consider the next idiom:

const isTruthy: <T>( x: T | false | undefined | null | '' ) => x is T
// not yet implemented

This declaration tells typescript that "this is a function that takes any type of parameter, and if it returns true it means the parameter is definitely not falsy". This is done by using Type guards through the return type "x is T". This is useful because it'll allow you to take a possible-falsy value and verify that it is, in fact, not falsy:

const a: any[] | null | undefined = [];
if(isTruthy(a)) {
  // a is any[]
}

One very simple way to implement isTruthy is by using the Boolean function:

type Falsy = null | undefined | false | 0 | ''
function isTruthy<T>(value: T | Falsy): value is T {
  return Boolean(value);
}

So, whats the point?

let's take a look at your example once again:

const check = (Boolean as any) as <T>(
  a: T | false | undefined | null | ''
) => a is T;
  1. Boolean in this code is a value. Specifically, it's the Boolean Function.
  2. it is cast to any and then cast to <T>( x: T | false | undefined | null | '' ) => x is T

So, all this code does is declare an alias for the Boolean function and tell TS that it is a type guard where if check(a) returns true, then a is not falsy.

Or you could, you know, just check the value itself:

type Falsy = null | undefined | false | 0 | ''
const a: string | Falsy = 'test'
if (a) {
  // a is inferred to be just "string"
}

TL;DR

your "check" function does some clever trickery to reuse the Boolean function to do exactly what a simple if() can already do.

Just check the truthiness of a value with if(value) and move on

<edit>

I missed an important part of the question:

Could someone please explain how this function would operate on an arrays inputs please? a sort of walk through of the syntax in this exampled would be helpful. Thanks.

in that case, your check function can be used with the filter method for some nice type inference:


const arr = ['a', false, 123, 0, '', null, undefined];

arr.filter(Boolean).forEach(value => {
  // value is possibly falsy even though the `filter` makes sure it isn't
});

const check = (Boolean as any) as <T>(
  a: T | false | undefined | null | ''
) => a is T;

arr.filter(check).forEach(value => {
  // value is string | number | true
});

This is because Typescript can't tell that the Boolean function also works just fine as a guard. So that's the one good use-case for your check function, though I'd rename it to isTruthy.

like image 65
Badashi Avatar answered Oct 24 '22 14:10

Badashi