Typescript: Type guards should be flowed

Created on 6 Sep 2016  路  3Comments  路  Source: microsoft/TypeScript

type A = number | string
function isNumber(_): _ is number { return typeof _ === 'number' }
const as: A[] = [1, 2, '3']

// (1) - OK: bs is number[]
let bs = as.filter(isNumber)

// (2) - Not OK - cs is still A[], but should be number[]
let cs = as.filter(_ => isNumber(_))

// (3) - Not OK - ds is still A[], but should be string[]
let ds = as.filter(_ => !isNumber(_))

Similar issues: https://github.com/Microsoft/TypeScript/issues/7657, https://github.com/Microsoft/TypeScript/issues/5101, https://github.com/Microsoft/TypeScript/issues/5951

Needs Proposal Suggestion

Most helpful comment

The request here is to infer user defined type guards from return expression of functions. i.e.:

function isNumber(a): a is number {
....
}

function myIsNumber(a) {
    return isNumber(a);  // should infer `a is number`
}

function isString(a: number | string) {
    return !isNumber(a);  // should infer `a is string`
}

All 3 comments

The request here is to infer user defined type guards from return expression of functions. i.e.:

function isNumber(a): a is number {
....
}

function myIsNumber(a) {
    return isNumber(a);  // should infer `a is number`
}

function isString(a: number | string) {
    return !isNumber(a);  // should infer `a is string`
}

I wish this issue got more attention because a bit of inference could go a long way.

I implemented a form of type predicate inference in 982c35fde3f3fe0a5a823456b27a45cb0618ce9c to get a feeling for the complexity. It goes beyond just propagating type predicates as outlined here and infers them as requested in #18572 and #19468. It's only a sketch and does not handle some common cases nor some of the edge cases I saw in other places that do type narrowing. That notwithstanding, I think the (implementation) complexity of an inference scheme for simple arrow types might be acceptable. However, I obviously lack the broader understanding necessary to properly assess this.

I want to emphasize how valuable an inference scheme like this could be. Manually specified predicates are not verified and thus error prone. The most common use case, as can be seen in #18572 and #19468, are filter functions. Anybody who uses rxjs in combination with redux or some other library that encourages flux standard actions likely has Observables of such actions and filters them by type. redux-observable has a dedicated function for this, which gives type safety at the cost of redundancy (both the type argument and the type must be specified.

Once again, I wish this issue would get more attention. =)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CyrusNajmabadi picture CyrusNajmabadi  路  3Comments

Zlatkovsky picture Zlatkovsky  路  3Comments

blendsdk picture blendsdk  路  3Comments

siddjain picture siddjain  路  3Comments

manekinekko picture manekinekko  路  3Comments