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

can't narrow from unknown to "not a number or bigint" #57899

Closed
ljharb opened this issue Mar 21, 2024 · 7 comments
Closed

can't narrow from unknown to "not a number or bigint" #57899

ljharb opened this issue Mar 21, 2024 · 7 comments
Labels
Duplicate An existing issue was already created

Comments

@ljharb
Copy link
Contributor

ljharb commented Mar 21, 2024

πŸ”Ž Search Terms

number bigint narrow

πŸ•— Version & Regression Information

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

⏯ Playground Link

https://tsplay.dev/wX09ow

πŸ’» Code

function nonNumeric(x: null | undefined | string | boolean | symbol | object, y: unknown) {
	return true;
}

function foo(x: unknown, y: unknown) {
	if (typeof x === 'number' || typeof x === 'bigint') {
		return false;
	}
	return nonNumeric(x, y);
}

πŸ™ Actual behavior

errors with Argument of type 'unknown' is not assignable to parameter of type 'string | boolean | symbol | object | null | undefined'.(2345)

πŸ™‚ Expected behavior

passes, because the typeof check ensures that unknown is properly narrowed to string | boolean | symbol | object | null | undefined.

Additional information about the issue

No response

@MartinJohns
Copy link
Contributor

I would say this is a design limitation.

unkown is not a union of the types you listed, so the compiler can't narrow the type in the else branch. This would require a type "unknown, except number", which would first require negated types (#4196).

@ljharb
Copy link
Contributor Author

ljharb commented Mar 22, 2024

Why isn't unknown a union of all possible types? I would expect it to be a named shorthand for null | undefined | string | boolean | number | bigint | symbol | object since that includes every possible JS value.

@MartinJohns
Copy link
Contributor

See: #39498 (comment)

@ljharb
Copy link
Contributor Author

ljharb commented Mar 22, 2024

oof, ok - that issue is actually my precise need for that exact same library. That's very unfortunate.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Mar 22, 2024
@craigphicks
Copy link

Consider this working code

function nonNumericTypeof(typeofx: "string" | "boolean" | "symbol" | "undefined" | "object" | "function") {
	return true; 
}

function foo(x: unknown) {
    const t = typeof x;
	if (t === 'number' || t === 'bigint') {
		return false;
	}
    t; // const t: "string" | "boolean" | "symbol" | "undefined" | "object" | "function"
    return nonNumericTypeof(t);
}

Conceivably, type information could embed the results of typeof comparisons (both true and false branches because typeof range is finite) . However, there are reasons why that very hard to integrate into current TypeScript, one of which is that number, string, etc. can be promoted to objects for type comparison.

@ljharb
Copy link
Contributor Author

ljharb commented Mar 23, 2024

How difficult it would be to achieve is entirely separate and not something I have knowledge of.

However, I can't conceive of any code where this narrowing would be incorrect, including your example.

@typescript-bot
Copy link
Collaborator

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

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Mar 26, 2024
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