Skip to content

Non-nullish assertion over property of generic object not respected #44698

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

Closed
LinusU opened this issue Jun 22, 2021 · 4 comments
Closed

Non-nullish assertion over property of generic object not respected #44698

LinusU opened this issue Jun 22, 2021 · 4 comments
Labels
Duplicate An existing issue was already created

Comments

@LinusU
Copy link
Contributor

LinusU commented Jun 22, 2021

Bug Report

I'm building a function that removes nullish-values from an object. In the code, that is generic over the object, TypeScript doesn't seem to respect my non-nullish assertion:

if (input[key] != null) result[key] = input[key]

It seems to think that input[key] could possibly be null in the assignment, even though the line is guarded by input[key] != null.

🔎 Search Terms

nullish assertion generics assignment

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about: v4.4.0-dev.20210622, v4.3.4, v4.3.2, v3.3.33

⏯ Playground Link

Playground link with relevant code

💻 Code

type PartialNonNullable<T> = { [P in keyof T]?: NonNullable<T[P]> }

function withoutNullishValues<T extends object> (input: T): PartialNonNullable<T> {
  const result: PartialNonNullable<T> = {}

  for (const key of Object.keys(input) as (keyof T)[]) {
    if (input[key] != null) result[key] = input[key]
  }

  return result
}

🙁 Actual behavior

Type 'T[keyof T]' is not assignable to type 'NonNullable<T[keyof T]> | undefined'.
  Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'NonNullable<T[keyof T]> | undefined'.
    Type 'T[string]' is not assignable to type 'NonNullable<T[keyof T]> | undefined'.
      Type 'T[string]' is not assignable to type 'NonNullable<T[keyof T]>'.
        Type 'T[keyof T]' is not assignable to type 'NonNullable<T[keyof T]>'.
          Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'NonNullable<T[keyof T]>'.
            Type 'T[string]' is not assignable to type 'NonNullable<T[keyof T]>'.

🙂 Expected behavior

no errors in type checking

@ArkaneMoose
Copy link

I believe this may be the same as my issue, #44446.

@fatcerberus
Copy link

If you're trying to narrow a generic type (we'll call it T), then TS can typically only represent the narrowing as T & NarrowerType (because within the generic function you don't know precisely what T is). In your case the necessary representation would be T & NOT null, which could only be done if we had negated types. See #4196.

@RyanCavanaugh
Copy link
Member

Generics can only be narrowed if they're a union, and T[keyof T] is not a union (it's effectively opaque from the checker's perspective), so no narrowing occurs here.

The implied suggestion here is to produce the narrowed type NonNullable<T[keyof T]> for input[key] inside the if; this is something we've experimented with but it's not as straightforward as it initially seems (at minimum for example, you need a new built-in type for every kind of narrowing, with associated higher-order behavior)

See #22348

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Jun 22, 2021
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

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