Skip to content

Type guard on unknown provides incorrect or "stale" editor hints #49093

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
alii opened this issue May 13, 2022 · 2 comments
Closed

Type guard on unknown provides incorrect or "stale" editor hints #49093

alii opened this issue May 13, 2022 · 2 comments

Comments

@alii
Copy link

alii commented May 13, 2022

Bug Report

When using type guard on unknown to narrow down a type, we can safely make assertions about an object, but the type information does not carry down for editor hints.

🔎 Search Terms

type, guard, editor, hint, incorrect, inlay

🕗 Version & Regression Information

  • Version 4.8.0-dev.20220512
  • This is the behavior in every version I tried

⏯ Playground Link

Playground link with relevant code

💻 Code

function hasProp<Prop extends string | number | symbol>(
	value: unknown,
	prop: Prop
): value is Record<Prop, unknown> {
	if (typeof value !== 'object') {
		return false;
	}

	if (!value) {
		return false;
	}

	return prop in value;
}

declare const test: unknown;

if (hasProp(test, "foo") && hasProp(test.foo, "bar") && typeof test.foo.bar === "boolean") {
    test.foo.bar;
    // ^? — this is typed as Record<"foo", unknown> when we actually know more info than it is telling us
}

🙁 Actual behavior

When hovering over test or using the // ^? syntax, it's visible that test is of type Record<'foo', unknown>, when really we have already asserted that there is more type information there available to us (e.g. .foo.bar` which is a boolean)

🙂 Expected behavior

The correct shape would appear, e.g.

const test: {foo: {bar: boolean}}
@alii alii changed the title Using Type guard provide incorrect editor hints Type guard on unknown provides incorrect or "stale" editor hints May 13, 2022
@fatcerberus
Copy link

fatcerberus commented May 13, 2022

All three of test, test.foo and test.foo.bar are narrowed correctly. The fact that test doesn't become { foo: { bar: boolean } } is expected - in general once you've arrived at Record<K, unknown> (whatever K happens to be), you can't infer anything further about its value type just by checking its individual properties. To put it another way, Record<K, string | number> doesn't suddenly become Record<K, string> just because you can't find any numbers in it right now.

Also, type guards on object properties never narrow the parent object in TS except in the case of discriminated unions. See #31755.

@alii
Copy link
Author

alii commented May 14, 2022

Ahh right, that makes perfect sense, thank you very much!

This comment was very useful:
image

@alii alii closed this as completed May 14, 2022
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

2 participants