Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Wait a second. How does the following even compile:

    function getSpellsForPerson(person: Person) {
      if (!isWizard(person)) {
        return [];
      }
      return person.spells;
    }
You can't return `person.spells` without type casting:

    return (<Wizard>person).spells;
or by accessing the field with array syntax:

    return person["spells"];
The latter one obviously discards type safety.


It's because the compiler uses the peculiar return type annotation on isWizard() to infer information about the argument and propagate it along one half of the control flow graph based on the result of isWizard().

It sees that the code `person.spells` is guarded by a truthful return from isWizard, and it trusts the annotation that person is Wizard as a result.


That's absolutely bonkers. What's the use case here? Also does that mean the following:

  console.log(person.spells); // <-- compilation error
  if (!isWizard(person)) {
    return[];
  }
  return person.spells; // <-- this is fine


The use case is having types depend on control flow so that guarded control flow paths don't need further typecasting. I don't see how this is bonkers. It looks like a great ergonomic feature to me.

As to your code, sure, it's an error. But it's not unusual, conceptually. For example:

    if (foo) {
      int bar = 22;
    }
    print(bar); // compilation error??
And this:

    if (foo) {
      print(bar); // compilation error??
      int bar = 22;
    }
More idiomatically, you'd expect to read code like this:

    if (isWizard(person)) { person.wizardStuff(); }
I think this is not an unusual thing to do in dynamically typed languages, especially when interfacing with third-party code where you can't easily add new polymorphic methods (so you can't rely on virtual dispatch to handle your if-case logic). Making it work more ergonomically in typescript isn't "absolutely bonkers".


Typescripts goal is to allow using existing JavaScript idioms while gaining the advantages of static type checking.

I don't think it's too bonkers for the type of a variable to change within the same scope, as long as there's some clear delineation. In rust you can redeclare a variable with the same name but different type:

    let x: i32 = 99;
    println!("{}", x);
    let x: &str = "shadows";
    println!("{}", x);
Kotlin does something very similar to typescript for null checks: https://kotlinlang.org/docs/reference/null-safety.html

I don't know what's so crazy about a variable's type changing within the same scope except that languages from before 2010 mostly didn't allow that.


To be clear, this doesn’t change the type in Rust. It creates a new variable with the same name. Very different thing!


This is confusing because the article fails at explaining how type guards actually works.


The type guard returns true if person is a wizard. The if statement handles the case that person is not a wizard. The only case left is that person is a wizard.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: