question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Suggestion: Type guard generic types

See original GitHub issue

Would it be good to have type guarding on generic types? Or was this decided against?

Example 1

class Parent {
    prop1: string;
}

class Child extends Parent {
    childProp: string;
}

var t: Parent = new Child();

if (t instanceof Child) {
    t.childProp; // no error
}

function myFunction<T extends Parent>(item: T) {
    if (item instanceof Child) {
        item.childProp; // error
    }
}

I realize this example could be rewritten without generics. It’s just an example 😃

Example 2

Here’s a scenario I came across when creating a wrapper class:

interface NedbItem {
    _id: string;
}

function isNedbItem(item: any): item is NedbItem {
    return item != null && typeof item._id === "string";
}

class DatabaseWrapper<T> {
    getItems() {
        const itemsFromDatabase: T[] = .....;

        itemsFromDatabase.forEach(i => this.stripNedbID(i));

        return itemsFromDatabase;
    }

    private stripNedbID(item: T) {
        if (isNedbItem(item))
        {
            delete item._id; // error, _id does not exist on T
        }
    }
}

Maybe a generic type with no constraint should be treated like an any type in this case? (Once type guards are fixed for any types – See #4432)

This suggestion is probably very low on the priority scale.

I couldn’t find this issue discussed elsewhere so sorry if it was.

Issue Analytics

  • State:open
  • Created 8 years ago
  • Reactions:18
  • Comments:15 (6 by maintainers)

github_iconTop GitHub Comments

3reactions
masaeeducommented, Jul 31, 2017

It seems like it already sort-of works if I explicitly write a generic function that returns the type guard:

class Cat { meow() { console.log("meow") } }
class Dog { woof() { console.log("woof") } }

class N<T extends Cat | Dog> {
    data: T = null
    print() {
        const data = this.data

        // This is fine
        if (is(data, Dog)) {
            return data.woof()
        }

        // Unfortunately, this is not. Looks
        // like narrowing isn't working.
        // return data.meow()

        // However, you can work around the
        // problem with this:
        if (is(data, Cat)) {
            return data.meow()
        }
    }
}

function is<T, TClass>(x: T, c: new () => TClass): x is T & TClass {
    return x instanceof c
}

Unfortunately, it looks like narrowing of the union doesn’t work. If I add the explicit annotation const data: Cat | Dog the error goes away, so it looks like an unfortunate interaction between union narrowing and generics. In the meantime, we can just explicitly write if-clauses for each case instead of relying on narrowing.

3reactions
ziahamzacommented, Sep 11, 2015

There are still valid cases where this can be helpful, especially when generic type extends from a union type. E.g


class Cat {    }
class Dog {  }
class Node<T extends Cat | Dog> {
     data: T = null
     print() {
          if (this.data instanceof Dog) {
                // this.data now has the type Dog inside the block
          }
     }
} 

But the example doesnt seem to work today as typescript does not specialise the generic type even if it is a subset of the type it extends from

Read more comments on GitHub >

github_iconTop Results From Across the Web

TypeScript Generics and Type Guards - Explained by Example
This article describes how we leveraged two TypeScript features: generics and type guards in writing a robust utility function.
Read more >
TypeScript Generics and Type Guards - Explained by Example
This article describes how we leveraged two TypeScript features: generics and type guards in writing a robust utility function.
Read more >
typescript - How to add extends type guards to conditional ...
Let's say I have a class with a generic parameter. It has conditional types on some of the class' properties. These conditional types...
Read more >
typing — Support for type hints — Python 3.11.1 documentation
This module provides runtime support for type hints. The most fundamental support consists of the types Any , Union , Callable , TypeVar...
Read more >
generic-type-guard - npm
generic -type-guard works with the TypeScript type system. You are guaranteed that the type guards you write are sufficient to prove that the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found