-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Type assertions & type predicates can have incorrect narrowing logic #57436
Comments
The primary reason to write a UDTG is to do type checks that the compiler isn't capable of doing itself, so it's very much intentional that the implementation isn't checked. Otherwise you'd get spurious errors in cases where the logic is sufficient for narrowing but the compiler isn't able to prove it. |
Could you share an example? The TS handbook doesn't seem to imply that, and in fact gives an example similar to mine that the compiler definitely was capable of doing itself. See "using type predicates" for example. I have yet to encounter a scenario where it is more useful for type predicates to not also have the compiler perform the checks it can. I've also seen many cases of people having the same mistaken understanding I do, so perhaps it would be beneficial to update the handbook to use such an example. I'd be happy to make that PR if I had such an example to propose. |
You’re basically asking TS to spit out an error whenever it thinks that you “haven’t done enough” to narrow the value according to the function signature, via the checks it’s able to do itself. Lots of non-trivial type guards would be broken by such an error; see #29980 (comment). tl;dr: The proposed behavior would error on any type predicate where the same check wouldn’t already work to narrow the value inline. In other words, almost all of them. |
The docs should probably be clearer about this |
This comment was marked as off-topic.
This comment was marked as off-topic.
example that may be useful for docs: interface SuccessStatus {
code: 0;
message: string;
}
interface FailureStatus {
/* in failure case code will be anything other than 0 */
code: number;
reason: string;
}
type ProcessStatus = SuccessStatus | FailureStatus;
function isSuccess(response: ProcessStatus): response is SuccessStatus {
return response.code === 0;
}
declare const a: ProcessStatus;
if (a.code === 0){
// this doesn't work since typescript can't determine that failure case can't be 0
console.log(a.message);
}
if (isSuccess(a)){
console.log(a.message); // works as intended.
} |
This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
@tadhgmister In the example you shared the type could be narrowed safely: interface SuccessStatus {
code: 0;
message: string;
}
interface FailureStatus {
/* in failure case code will be anything other than 0 */
code: number;
reason: string;
}
type ProcessStatus = SuccessStatus | FailureStatus;
function isSuccess(response: ProcessStatus): response is SuccessStatus {
return 'message' in response;
}
declare const a: ProcessStatus;
if (a.code === 0){
// this doesn't work since typescript can't determine that failure case can't be 0
console.log(a.message);
}
if ('message' in a){
// this works and is verifiable by the compiler
console.log(a.message);
}
if (isSuccess(a)){
console.log(a.message); // works as intended.
} It seems like it would be preferable to have the narrowing occur safely, and that seems to be the standard expectation of TS developers who are unfamiliar with the current behavior. |
@Masstronaut then consider a case where message and reason are both optional. (Playground Link) I do think my original example is sufficient to get the point across but I respect your need for an example that has no alternative. |
🔎 Search Terms
Type assertion, type predicates, type narrowing
🕗 Version & Regression Information
⏯ Playground Link
see on TS playground
💻 Code
🙁 Actual behavior
An assertion function or type predicate which contains insufficient logic to narrow the input type generates no errors and can be used to narrow a type in the calling code, despite not having certainty the type is narrower.
🙂 Expected behavior
an assertion function or type predicate which doesn't sufficiently narrow the input type before the return or end of function should result in an error.
Additional information about the issue
No response
The text was updated successfully, but these errors were encountered: