IssueRaiser

Suggestion: one-sided or fine-grained type guards

## The Problem User-defined type guards assume that *all* values that pass a test are assignable to a given type, and that *no* values that fail the test are assignable to that type. This works well for functions that strictly check the type of a value. ```ts function isNumber(value: any): value is number { /* ... */ } let x: number | string = getNumberOrString(); if (isNumber(x)) { // x: number } else { // x: string } ``` But some functions, like `Number.isInteger()` in ES2015+, are more restrictive in that only *some* values of a given type pass the test. So the following does't work. ```ts function isInteger(value: any): value is number { /* ... */ } let x: number | string = getNumberOrString(); if (isInteger(x)) { // x: number (Good: we know x is a number) } else { // x: string (Bad: x might still be a number) } ``` The current solution – the one followed by the [built-in declaration libraries][1] – is to forgo the type guard altogether and restrict the type accepted as an argument, even though the function will accept any value (it will just return `false` if the input is not a number). ```ts interface NumberConstructor { isInteger(n: number): boolean; } ``` ## A Solution: an "as" type guard There is a need for a type guard that constrains the type when the test passes but not when the test fails. Call it a *weak type guard*, or a *one-sided type guard* since it only narrows one side of the conditional. I would suggest overloading the `as` keyword a

Posted by mcmath on Apr 6, 2017, 12:19 PM

Tags

Related issues

Raise real-world problems, find people facing the same issue, and discuss solutions.4,500 issues0 comments

reliability (Other)

Suggestion: one-sided or fine-grained type guards

mcmathApr 6, 2017, 12:19 PM

## The Problem User-defined type guards assume that *all* values that pass a test are assignable to a given type, and that *no* values that fail the test are assignable to that type. This works well for functions that strictly check the type of a value. ```ts function isNumber(value: any): value is number { /* ... */ } let x: number | string = getNumberOrString(); if (isNumber(x)) { // x: number } else { // x: string } ``` But some functions, like `Number.isInteger()` in ES2015+, are more restrictive in that only *some* values of a given type pass the test. So the following does't work. ```ts function isInteger(value: any): value is number { /* ... */ } let x: number | string = getNumberOrString(); if (isInteger(x)) { // x: number (Good: we know x is a number) } else { // x: string (Bad: x might still be a number) } ``` The current solution – the one followed by the [built-in declaration libraries][1] – is to forgo the type guard altogether and restrict the type accepted as an argument, even though the function will accept any value (it will just return `false` if the input is not a number). ```ts interface NumberConstructor { isInteger(n: number): boolean; } ``` ## A Solution: an "as" type guard There is a need for a type guard that constrains the type when the test passes but not when the test fails. Call it a *weak type guard*, or a *one-sided type guard* since it only narrows one side of the conditional. I would suggest overloading the `as` keyword a

Comments (0)

No comments yet. Start the discussion.

Comment on this issue