Hacker News new | ask | show | jobs
by fuzzy2 1544 days ago
This is called Type Narrowing by the way. Control flow analysis is only one way this works in TypeScript.

Most languages don’t have the type system necessary to make this work in a sensible way.

1 comments

In Kotlin this is called smart casts. It works great.

Doing a null check means that after that you can treat the variable as non nullable. Doing a type check, narrows down the type to what you just checked. Or going down a switch statement branch on the type actually implicitly does the cast as well.

It's both strongly typed and convenient.

Kotlkin even goes a step further and introduced contracts few versions ago that you can bind to functions. For example calling isNullOrBlank() on a nullable string changes to the type to nullable if the answer is false. You can write your own contracts for your own functions even. This is what the source code for this function looks like:

  @kotlin.internal.InlineOnly
  public inline fun CharSequence?.isNullOrEmpty(): Boolean {
    contract {
        returns(false) implies (this@isNullOrEmpty != null)
    }

    return this == null || this.length == 0
  }
I guess typescript does something similarish.
Yeah, they're called "type predicates" (or "type guards"). So you can do something like

    function isFish(pet: Fish | Bird): pet is Fish {
      return (pet as Fish).swim !== undefined;
    }
and Typescript is smart enough to let you use it in an if-branch

    // Both calls to 'swim' and 'fly' are now okay.
    let pet = getSmallPet();
 
    if (isFish(pet)) {
      pet.swim(); 
    } else {
      pet.fly();
    }
Typescript also has typechecker support for assertion functions. So like,

    function assertIsDefined<T>(val: T): asserts val is NonNullable<T> {
      if (val === undefined || val === null) {
        throw new AssertionError(`Expected 'val' to be defined, but received ${val}`);
      }
    }
Which we can use like so:

    function doSomething(pet: Fish | undefined) {
      assertIsDefined(pet);

      // safe to use without checking for null/undefined,
      // because our assertion function narrowed the type for 
      // usage later in the function 
      pet.swim();
    }
>For example calling isNullOrBlank() on a nullable string changes to the type to nullable if the answer is false

For anyone confused like I was, that's a typo, it changes the type to not nullable. Likewise, isNullOrBlank() is an extension of the listed isNullOrEmpty().

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/is-...

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/is-...