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

Arrow functions cannot be used as user-defined type guards #5951

Closed
pimterry opened this issue Dec 6, 2015 · 4 comments
Closed

Arrow functions cannot be used as user-defined type guards #5951

pimterry opened this issue Dec 6, 2015 · 4 comments
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead

Comments

@pimterry
Copy link
Contributor

pimterry commented Dec 6, 2015

User defined type guards work perfectly well for classic function statements, as in the release notes:

interface Animal {name: string; }
interface Cat extends Animal { meow(); }

function isCat(a: Animal): a is Cat {
  return a.name === 'kitty';
}

However, it appears that the arrow function equivalent isn't acceptable:

// Doesn't compile
var isReallyCat: (a: Animal) => a is Cat = (cat) => cat.name === 'kitty';

This gives "Type '(cat: Animal) => boolean' is not assignable to type '(a: Animal) => a is Cat'. Signature '(cat: Animal): boolean' must have a type predicate". I'm not clear how I would give that arrow function a 'type predicate', beyond what's already included here.

Is there a good reason for this? I can't seem to find it documented anywhere.

@Arnavion
Copy link
Contributor

Arnavion commented Dec 6, 2015

Using a type assertion instead of type annotation does work

var isReallyCat = <(a: Animal) => a is Cat>((cat) => cat.name === 'kitty');

so I imagine it's just an oversight rather than deliberate.

@DanielRosenwasser DanielRosenwasser added the By Design Deprecated - use "Working as Intended" or "Design Limitation" instead label Dec 6, 2015
@DanielRosenwasser
Copy link
Member

The issue is that you don't want a boolean-returning function to be assignable to a type-guard.

function isHippopotamusFood(a: Animal): boolean {
    // ...
}

let isReallyCat: (a: Animal) => a is Cat = isHippopotamusFood;

For that reason, type predicates need to be placed on the return type of the function proper. The declaration itself needs to opt in.

The following also works:

```ts
var isReallyCat: (a: Animal) => a is Cat = (cat): cat is Cat => cat.name === 'kitty';

or just

var isReallyCat = (cat): cat is Cat => cat.name === 'kitty';

We could contextually type the return type to be a type predicate when appropriate, but I don't know if it'd really be worth it, and we usually never touch return types when performing contextual typing.

@Arnavion
Copy link
Contributor

Arnavion commented Dec 6, 2015

The issue is that you don't want a boolean-returning function to be assignable to a type-guard.

Why not? Nothing prevents me from implementing a x is Foo function with Math.random() either.

@DanielRosenwasser
Copy link
Member

Sure, but you have to intentionally opt in to that, and if you're totally sure you want to sabotage your users' experiences, more power to you. We're trying to avoid people from accidentally assigning an arbitrary function to a type predicate.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
By Design Deprecated - use "Working as Intended" or "Design Limitation" instead
Projects
None yet
Development

No branches or pull requests

3 participants