eslint-plugin-unicorn: `no-array-callback-reference` rule is not compatible with TypeScript type guards

function isDefined<T>(argument: T | undefined): argument is T {
  return typeof argument !== 'undefined'
}

const items = [1, 2, undefined]

items.filter(isDefined).map((number) => {
  // number is now type guarded and undefined is eliminated
  console.log(number)
})

items.filter((num) => isDefined(num)).map((number) => {
  // however, this way it does not work, and "number" can still be undefined
  console.log(number)
})

I am not sure why TypeScript is not inferring the results in the second way.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 9
  • Comments: 20 (3 by maintainers)

Most upvoted comments

+1, I’d love to see a fix to this rule so I can stop disabling it on all inline typeguards.

The typeguard info is lost because the wrapper function is not a typeguard. If you simply make your wrapper function a typeguard then problem fixed.

e.g.

items.filter((num): num is number => isDefined(num)).map((number) => {
  console.log(number + 1);
});

playground link

Though this being said, typeguards probably should be ignored by this rule (probably via an option like @Vages suggests (I would suggest the option be named ignoreTypeGuards or allowTypeGuards)) as typeguards are highly unlikely to change their parameter signature.

This should be trivial for cases where the function exists in the same file I’m not sure about what to do when the function is imported, though.

It shouldn’t make any difference if the function is defined in the same file or not; all the information needed is in the function’s type information.

If people want this, I can make a PR (I’m the main contributor for eslint-plugin-functional so I’m pretty experienced with working with eslint rules).

Hi, the issue is described here: https://github.com/microsoft/TypeScript/issues/10734 and here: https://github.com/microsoft/TypeScript/issues/16069. Would it be sensible to add an exception for functions with type guards (either by default or through an option)?

With an experienced eslint-rulemaker like you, @RebeccaStevens, making the extension, I’m quite certain that the lint-rule should just ignore type-guards by default (in hindsight, I think I only suggested it due to a lack of confidence in my lint-rule abilities 😅). Having an option for it seems bloated, and if this actually affects someone negatively (which I really doubt), we could add the option in later.

I’m only an ordinary contributor myself, but if you make a PR, I could test it and give some feedback. Just tag me when you add it. PS: I use eslint-plugin-functional; good work!

@oss6 thanks for finding the proper references!

Expect

items.filter(((num) => isDefined(num)) as typeof isDefined).map((number) => {
  // however, this way it does not work, and "number" can still be undefined
  return number + 1
})

?