Skip to content

Unlisted properties type narrowing seems to be working only for actual property access but the type is still incorrect on the object itself #51739

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
LunarMelody opened this issue Dec 3, 2022 · 5 comments

Comments

@LunarMelody
Copy link

Bug Report

With the release of TS 4.9 type narrowing was improved and we can use it to check for presence of some certain keys and their types in unknown objects, which works fine if we were to access the property like foo.bar and it would be, for example, a string. However, the type is incorrect for the object itself even after checking for the property's type and would result in object & Record<"bar", unknown>.

// the object
const foo = {
  bar: "string!",
}

🔎 Search Terms

  • type narrowing with in
  • property type narrowing
  • "in" type narrowing

🕗 Version & Regression Information

  • I was unable to test this on prior versions because the type narrowing was introduced in the recent version.

⏯ Playground Link

Playground link with relevant code

💻 Code

interface IFoo {
  bar: string;
}

const foo: IFoo = {
  bar: "bar",
};

const theFunction = () => {
  const jsonified = JSON.stringify(foo);
  const parsed: unknown = JSON.parse(jsonified);

  if (typeof parsed !== "object" || parsed == null) {
    throw Error("We parsed somethign that aint an object! D:");
  }

  if (!("bar" in parsed)) {
    throw Error("bar is not in foo! D:");
  }

  if (typeof parsed.bar !== "string") {
    throw Error("the foo in the bar is not a string! D:");
  }
  // type error, "unknown" is not assignable to "string"
  const result = { ...parsed } satisfies IFoo;
};

🙁 Actual behavior

Object doesn't infer types after unlisted property type checking, i.e. object & Record<"bar", unknown>

🙂 Expected behavior

Object should know the type of a key after unlisted property type check, i.e. object & Record<"bar", string>

@LunarMelody LunarMelody changed the title Unlisted properties type narrowing looks to be working only when we access the property we've checked Unlisted properties type narrowing seems to be working only for actual property access but the type is still incorrect on the object itself Dec 3, 2022
@LunarMelody
Copy link
Author

LunarMelody commented Dec 3, 2022

Another interesting thing tho, is that when doing destructuring variable assignment it kinda works 50/50 here. VSCode seems to be able to tell the type after you write it, but it can't until then.

Here's bar is unknown

image

And now here bar is a string

image

@Andarist
Copy link
Contributor

Andarist commented Dec 3, 2022

It's a more general problem - not directly related to the new narrowing capabilities of unknown.

TypeScript only narrows down property types but this doesn't affect their parent object types at all. Notice how in this playground the type of test stays always unaffected and that even accept is not happy about this object despite the fact that we already have narrowed down test.foo

@MartinJohns
Copy link
Contributor

MartinJohns commented Dec 3, 2022

@Andarist That's intentional / design limitation. See #42384 for more details.

But IMO that suggestion would be unsafe anyway, because the object is mutable. Nothing stops the code from changing foo to a number.

@fatcerberus
Copy link

fatcerberus commented Dec 3, 2022

On the other hand, see #50891, which is itself a duplicate of #42384 but notable for being posted by a TS team member.

@LunarMelody
Copy link
Author

I see, thanks for details!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants