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

User defined type guard function and type any #5930

Closed
Strate opened this issue Dec 4, 2015 · 9 comments
Closed

User defined type guard function and type any #5930

Strate opened this issue Dec 4, 2015 · 9 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@Strate
Copy link

Strate commented Dec 4, 2015

Hi all!

interface A {
    prop: string
}

function isA(arg: any): arg is A {
    return "prop" in arg;
}

function handle(arg: any) {
    if (isA(arg)) {
        let b = arg.nonExistsProp; // no compile error here
    }
}

Why there is no compile error while acessing nonExistsProp? Is it by design and guard function only works with union types? Can't find some sort of specs, please, help me.

@RyanCavanaugh
Copy link
Member

Type guards do not narrow any. The reasoning for this is that we want type guards to allow you to do more, not less. any can already do everything, so it doesn't "help" you in that regard.

More specifically, we actually did try it the other way. The initial version of type guards did narrow on any; what we found is that a lot people had code like this:

// By contract, this function accepts only a Dog or a House
function fn(x: any) {
  // For whatever reason, user is checking against a base class rather
  // than the most-specific class. Happens a lot with e.g. HTMLElement
  if (x instanceof Animal) {
    x.woof(); // Disallowed if x: Animal
  } else {
    // handle House case
  }
}

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label Dec 5, 2015
@DanielRosenwasser
Copy link
Member

At the expense of being pedantic, this isn't entirely true. instanceof and user-defined type guards do not perform narrowing. typeof type guards do because we know exactly what type a value has.

let x: any;

if (typeof x === "number") {
    // 'x' has type 'number' here.
    let y = x * x;
}

@zpdDG4gta8XKpMCd
Copy link

@RyanCavanaugh what bothers me is that the design team is up for encouraging bad habits, this is wrong, please stop, you cannot follow the flow even if everyone flows with it, you should make what's right, not what's everyone is accustomed to be doing for their lives, i mean an average member of javascript community doesn't have a PhD in computer science, why the hell we choose to follow his bad habits?

type guard should narrow things, this is what they do, narrowing any makes perfect sense

@fongandrew
Copy link

+1 on changing the behavior to narrowing the type.

With respect to prior user behavior, I don't think it's something to be encouraged, but if it is widespread, it's because instanceof existed prior to typeguards being introduced. For user-defined typeguards however, that's not the case. If I define a function with the signature (arg: any) => arg is A, there's zero ambiguity that the user intends for any type to be narrowed to A.

Alternatively, maybe there could be some sort of syntax where the user can explicitly indicate intent to narrow? E.g. isA(arg: any) => arg isOnly A?

@RyanCavanaugh
Copy link
Member

I'm serious about the number of breakages we found in real-world code. It was very large, and feedback from people trying early builds said they didn't want this.

It's so far been basically impossible to get a type error on a value of type any and there would need to be a stronger justification other than "You should be stricter on people" when the entire point of the any type is to be as unstrict as possible.

On the one hand, listen to users, and on the other hand, listen to users...

@zpdDG4gta8XKpMCd
Copy link

Don't see a contradiction. Let any be the most unrestricted thing in the world. No problem. But when someone does if (anything is Potato) { eatSteak(anything); } they expect a compiler error, any won't give it to them, so they don't want any, they want a shaped value. So the strictness is welcome here, it's a good thing, why would anyone be pissed by it.

@RyanCavanaugh
Copy link
Member

What you've written there is runtime-invalid code. The point is that there's lots of runtime-valid code that also issues a type error if we narrow any

@zpdDG4gta8XKpMCd
Copy link

Let's not use word strictness or narrowing for a second. Type guard is a predicate that asserts at runtime that a given value is of certain type. Ultimately one can put anything in it and it would say yes or no. Once it said yes you get a guarantee (up to the implementation of the type guard) that a value is of that type. Am I right so far? If so, then your example with the woof method must break. We asserted that a value is of type Animal. Animals don't woof, dogs do. It's not a runtime valid code, because if I put a cat in that function it will crash regardless of what the author thought the contract is. There is no such thing as a contract in JavaScript, there are only our best assumptions and hopefully a test that verifies them. So I am not sure why we are into giving the developers an illusion that they know what they are doing. I see your point that there are a lot of naive people who already written tons of crappy code, well this is TypeScript for goodness sake, time to grow up.

@zpdDG4gta8XKpMCd
Copy link

I am not trying to convince you. Just ranting. I get it that the design goal is to make a mainstream language that fits the least competent developer. It is indeed very frustrating that correctness isn't the goal. I get that too. There is already quite a number of features that I wish didn't exist at all, we one more one less doesn't make a difference. Hopefully the niche for a correct/sound counterpart of TypeScript will be filled soon. As soon as we have it we will get a natural partitioning between the skilled developers and beginners.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

6 participants