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

Unexpected types when using isNullish/isNonNullish in conditional #675

Open
JeongJuhyeon opened this issue May 8, 2024 · 2 comments
Open
Labels
bug Something isn't working help wanted Extra attention is needed typing Something type related

Comments

@JeongJuhyeon
Copy link

JeongJuhyeon commented May 8, 2024

TS Version: 5.4.5

Example:

pipe(
      [{ x: 10 }, { x: 20 }], 
      firstBy(prop("x")), 
      conditional(
        [isNullish, (o) => o], // got "o: never", expected "o: undefined"
        [isNonNullish, (o) => o] // got: "o: {}", expected: "o: { x: number; }"
      )
    );

I checked separately if it had to do with the FirstBy type but that doesn't seem to be the case:

const k1 = pipe([{ x: 10 }, { x: 20 }], firstBy(prop("x"))); // FirstBy<{x: number; }[]>, as expected
type t1 = Extract<typeof k1, null | undefined>; // undefined, as expected
type t2 = NonNullable<typeof k1>; // {x: number; }, as expected

It looks like the conditional's Whens must be a type guard of the form is A where A is a primitive type, so not even "NonNullable". Is this correct and intended? If so, it would be good to reflect this in the documentation.

@JeongJuhyeon JeongJuhyeon changed the title Unexpected behavior when using isNullish/isNonNullish in conditional Unexpected types when using isNullish/isNonNullish in conditional May 8, 2024
@eranhirsch
Copy link
Collaborator

We've got other reports about conditional acting different than expected for people. It's most likely a bug in our typing for conditional.

@eranhirsch eranhirsch added bug Something isn't working help wanted Extra attention is needed typing Something type related labels May 8, 2024
@grigorischristainas
Copy link
Contributor

@eranhirsch I tried to modify the guards as a workaround and I think isNullish could be modified as follows:

import type { NarrowedTo } from "./internal/types";

export function isNullish<T>(
  data: T | null | undefined,
): data is NarrowedTo<T, null | undefined> {
  return data === null || data === undefined;
}

This narrowing allows for o in the example above being inferred as null | undefined, which I think is correct.

However, I am not sure what can be done about isNonNullish. Best I could do by modifying the guard is end up with o being inferred as unknown in conditional.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed typing Something type related
Projects
None yet
Development

No branches or pull requests

3 participants