5

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;
4
  • 1
    It would just return true for array inputs, since all arrays are truthy. Commented Dec 23, 2020 at 18:50
  • Really weird function :D Commented Dec 23, 2020 at 19:14
  • @Aplet123 are you able to break it down please with an example, I don't understand it really and I'm not sure what the <T> followed by parentheses means either? Commented Dec 23, 2020 at 19:49
  • never be sure about javascript: Boolean = (()=> false) as typeof Boolean; :D Commented Dec 23, 2020 at 20:00

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

13 Comments

Great answer, but you missed at least one falsey value....
unfortunately there's no NaN type on Typescript, it's always a number.
You can't do a literal type with NaN like you can with other numbers? Interesting!
There is a two year old discussiob on github about NaN type: github.com/Microsoft/TypeScript/issues/28682
@Badashi I agree with Jared Smith, your answer is great!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.