Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type not automatically changing after .filter #47194

Closed
git-no opened this issue Dec 19, 2021 · 7 comments
Closed

Type not automatically changing after .filter #47194

git-no opened this issue Dec 19, 2021 · 7 comments
Labels
Duplicate An existing issue was already created

Comments

@git-no
Copy link

git-no commented Dec 19, 2021

Bug Report

Type not automatically changing after .filter

🔎 Search Terms

typescript error filter undefinied

Found
issue 20707
issue 20812

🕗 Version & Regression Information

Typescript 4.5.3 and below
ESNext and below

Please keep and fill in the line that best applies:

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about _________

⏯ Playground Link

Playground Link

💻 Code

const mixedArray = ['string',undefined,'string'] // result of await Promise.all(apps.map(app => fetchData(app)))

// none of them following new arrays are just type string[], they are still (string | undefined)[]
const shouldBeStringArray = mixedArray.filter(v => v != undefined)
const shortVersionShouldBeStringArray = mixedArray.filter(v => !!v)
const typeCheckShouldBeStringArray = mixedArray.filter(v => {return typeof v == "string"})

🙁 Actual behavior

const mixedArray = ['string',undefined,'string'] // result of await Promise.all(apps.map(app => fetchData(app)))
const shouldBeStringArray = mixedArray.filter(v => v != undefined)
// shouldBeStringArray is type (string | undefined)[]

🙂 Expected behavior

const mixedArray = ['string',undefined,'string'] // result of await Promise.all(apps.map(app => fetchData(app)))
const shouldBeStringArray = mixedArray.filter(v => v != undefined)
// shouldBeStringArray type string[]
@MartinJohns
Copy link
Contributor

Duplicate of #20218. You're not passing a type guard function to filter.

@Jamesernator
Copy link

Jamesernator commented Dec 19, 2021

In these situations I feel like it would be helpful for TypeScript to infer these functions as typeguards automatically. In particular if we have one of the following callbacks to infer as a typeguard:

v => v != undefined; // or null
v => typeof v === "string"; // and others
v => v instanceof SomeClass;
v => v === "someLiteral"; // and other types
// ideally disriminants as well but this might be harder to statically analyze
v => v.kind === "someKind"

@MartinJohns
Copy link
Contributor

@Jamesernator See #38390.

@git-no
Copy link
Author

git-no commented Dec 19, 2021

Duplicate of #20218. You're not passing a type guard function to filter.

Im doubt that it would work. I do miss your specific solution.

This type guard does not work correct

type A = string | undefined
const array: A[] = ['hello', undefined, 'salve'];
const a1 = array.filter((e): e is string => e == undefined);

because a1 is type string[] but got no string value, got only undefined.
Conclusion, Typescript has the next error, it does not check the types assigned to a1. There is no warning.

@git-no
Copy link
Author

git-no commented Dec 19, 2021

Potential Solution

This solution works

// Create this helper function
function isNotNullOrUndefined<T extends Object>(input: null | undefined | T): input is T {
    return input != null;
}

// This actually determines that result is of type (string)[]
let correctStringArray = mixedArray.filter(isNotNullOrUndefined);

Source / found in 16069

@MartinJohns
Copy link
Contributor

This type guard does not work correct

Type guards are not checked for correctness. You can say the very same about the helper function from your last comment.

@conartist6
Copy link

conartist6 commented Dec 22, 2021

iter-tools contains a bunch of type guards (referred to there as predicates), and is the only library I know of that has:

  1. users
  2. not guards (which are critical because the types are written differently)
  3. the guards you need (as of v7.2.0, which I just released)

I should probably split this out into a separate @iter-tools/predicates package, but I have not done this yet.

The method it sounds like you want is notNil.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants