question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Array.prototype.filter doesn't require callback to return

See original GitHub issue

I dig a bit and found out in #5850 and subsequently in #7779 the signature of filter has been changed not to return a boolean, so that people could return a truthy value in the implementation of the filter.

While I undertand the convenience in terms of ease of use, this as far as I observed puts developers at risk of simple bugs like the following:

const even = [1,2,3].filter(x => {
    x % 2 == 0
})

Notice the missing return statement means the function returns undefined, which translates to false, which filters all the items out. This applies also in the case of noImplicitReturns set to true, since the function return type is any, thus it could be a void function for what the compiler knows.

I believe TypeScript’s job should be to put this kind of cases in check actually, so that things like truthy values (which sometimes aren’t as obvious as we might think and introduce bugs we don’t really understand) can be better taken care of.

One solution to make both parties happy would be to optionally support truthy values (maybe an extra compiler flag? Another truthy type to allow for more relaxed checking?) and reintroduce the original signature of filter.

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:9
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
aj-rcommented, Feb 4, 2018

A TruthyFalsy type would also allow us to catch bugs in if statements - we could add a compiler option for strictIfConditions or something, which requires the condition of an if statement to be a boolean or TruthyFalsy type. For example:

function isReady(): boolean {
    return false;
}

if (isReady) { // compile error: type '() => boolean' is not allowed in an 'if' condition. Only types 'boolean' or 'TruthyFalsy' are allowed.
}

The bug here, of course, is that we should have done if (isReady()) instead of if (isReady). But currently typescript will not catch that bug, and the code will execute as if isReady is always true.

Same for && and || operators - we could require both operands to be TruthyFalsy.

However, this could end up being overly restrictive. I often like to do if (x) to check if x is not undefined, which would be prohibited. I also like to do const y = x || "default"; (using || as sort of a null-coalescing operator), which would also be prohibited.

As a workaround, we could allow null or undefined types in addition to TruthyFalsy and boolean types. But this seems like a strange/unexpected exception to the rule. Alternatively, we could allow any type except function types, just to prevent this specific bug - then this becomes independent of the TruthyFalsy type.

1reaction
denis-sokolovcommented, Mar 8, 2018

I understood the TruthyFalsy type to be any type that has at least one truthy and one falsy value. A { foo: number } | null obviously matches. A boolean, string or number also do because they inherently have falsy values. However, neither { foo: 3 }, nor () => {}, nor "string-literal" would match because they are always truthy. Neither undefined, nor null, because they are always falsy. We then need an exception to make literal true or false match TruthyFalsy. This will ensure that we can have “always true” or “always false” filters as well as use constant values in conditions: const DEBUG = false; if (DEBUG) { ... }.

@aj-r, you say it could be overly restrictive. I don’t understand. What am I missing in your examples?

if (x) to check if x is not undefined, which would be prohibited.

If x is { foo: number } | undefined, then it would be allowed, that matches TruthyFalsy, it would not be prohibited. If x is always truthy or always undefined, then the condition is meaningless, and it’s great that it’s prohibited, no?

I also like to do const y = x || "default"; (using || as sort of a null-coalescing operator), which would also be prohibited.

Again, if x can be truthy and falsy, this would not be prohibited. If it’s always truthy or always falsy, the code above is a programmer error, so it’s good it’s prohibited.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Array.prototype.filter() expects a value to be returned at the ...
5. Filter method only returns those elements for which its callback returns true. Solution: 1. · 3. You need to use map function...
Read more >
Array.prototype.filter() - JavaScript - MDN Web Docs
A function to execute for each element in the array. It should return a truthy to keep the element in the resulting array,...
Read more >
The JavaScript Array.filter() method - Debbie O'Brien
The filter() method calls a callback function once for each element in an array and constructs a new array for all the values...
Read more >
array-callback-return - ESLint - Pluggable JavaScript Linter
Array has several methods for filtering, mapping, and folding. If we forget to write return statement in a callback of those, it's probably...
Read more >
filter · WebPlatform Docs
Returns the elements of an array that meet the condition specified in a callback function. Syntax. filter( callbackfn [, thisArg ]). callbackfn: Required....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found