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.

Enable type parameter lower-bound syntax

See original GitHub issue

TypeScript Version: 2.1.1

Code

class Animal {}
class Cat extends Animal {}
class Kitten extends Cat{}

function foo<A super Kitten>(a: A) { /* */ }

Expected behavior: The type parameter A has the type Kitten as lower-bound.

Actual behavior: Compilation failure. The syntax is unsupported.

Discussion: The upper-bound counterpart of the failed code works fine:

class Animal {}
class Cat extends Animal {}
class Kitten extends Cat{}

function foo<A extends Animal>(a: A) { /* */ }

People in issue #13337 have suggested to use

function foo <X extends Y, Y>(y: Y) { /* */ }

to lower-bound Y with X. But this does not cover the case where X is an actual type (instead of a type parameter).

Issue Analytics

  • State:open
  • Created 7 years ago
  • Reactions:92
  • Comments:30 (4 by maintainers)

github_iconTop GitHub Comments

73reactions
jyuhuancommented, Mar 7, 2017

@RyanCavanaugh : In short, it mimics contravariance, just as extends mimics covariance.

We will try to sort an array of cats to see the necessity of this feature.

To do comparison-based sorting, we need a Comparator interface. For this example, we define it as follows:

interface Comparator<T> {
  compare(x: T, y: T): number
}

The following code shows that the class Cat has Animal as its super-class:

class Animal {}
class Cat extends Animal {}

Now we can write a sorting function that supports arbitrary Cat comparators as follows:

function sort(cats: Cat[], comparator: Comparator<Cat>): void {
  // Some comparison-based sorting algorithm.
  // The following line uses the comparator to compare two cats.
  comparator.compare(cats[0], cats[1]);
  // ...
}

Now, we will try to use the sort function. The first thing is to implement a CatComparator:

class CatComparator implements Comparator<Cat> {
  compare(x: Cat, y: Cat): number {
    throw new Error('Method not implemented.');
  }
}

Then we create a list of Cats,

const cats = [ new Cat(), new Cat(), new Cat() ]

Now we can call sort as follows without any problem:

sort(cats, new CatComparator());

We have not seen the need for contravariance so far.

Now, suppose we are told that someone has already implemented a comparator for Animals as follows:

class AnimalComparator implements Comparator<Animal> {
  compare(x: Animal, y: Animal): number {
    throw new Error('Method not implemented.');
  }
}

Since a Cat is also an Animal, this AnimalComparator is also able to handle Cats, because the compare function in AnimalComparator takes two Animals as input. I can just pass two Cats to it and there will be no problem.

Naturally, we would want to use AnimalComparator for sort too, i.e., call the sort function as:

sort(cats, new AnimalComparator());

However, since the following two types:

  • Comparator<Animal>
  • Comparator<Cat>

are not related from the point of view of TypeScript’s type system, we cannot do that.

Therefore, I would like the sort function to look like the following

function sort<T super Cat>(cats: Cat[], comparator: Comparator<T>): void {
  // Some comparison-based sorting algorithm.
  // The following line uses the comparator to compare two cats.
  comparator.compare(cats[0], cats[1]);
  // ...
}

or as in Java,

function sort(cats: Cat[], comparator: Comparator<? super Cat>): void {
  // Some comparison-based sorting algorithm.
  // The following line uses the comparator to compare two cats.
  comparator.compare(cats[0], cats[1]);
  // ...
}

I am aware of the fact that TypeScript does not complain if I pass AnimalComparator to sort. But I would like TypeScript’s type system to explicitly handle type lower-bounds. In fact, the current type system of TypeScript will let some type error closely related to this issue silently pass the compiler’s check (see issue #14524).

65reactions
thw0rtedcommented, Jun 3, 2021

Is there any chance of moving this along from “Discussion” phase, @RyanCavanaugh ? Several other issues about e.g. the signature of Array#includes / Array#indexOf have been closed in favor of this one, but the team doesn’t seem to be involved here at all.

It don’t think it’s controversial that this should pass type checking:

declare const n: number;
const arr = [1,2,3] as const;
arr.includes(n);

At least, I haven’t seen anybody in any of the related threads identifying this construct – specifically for methods on const arrays of primitive literals – as “error prone”. If I’m right, and allowing this is uncontroversial, what’s the next step in moving towards a solution?

If I’m wrong, and it is controversial, a) why?, and b) what’s a better / safer way to write the above?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Bounded Type Parameters - The Java™ Tutorials
To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound, which in...
Read more >
Is it possible to specify both upper and lower bound ...
Is it possible to specify both upper and lower bound constraints on type parameters in Java? I found a conversation ...
Read more >
BOUND Function
Syntax. BOUND (value, type, ignore, value1, value2 [,ignore(n), ... Use the ignore parameter to disable constraints by a particular range.
Read more >
Java Generics FAQs - Type Parameters
In order to allow the invocation of the compareTo method we must tell the compiler that the unknown Key type has a compareTo...
Read more >
Java Generics Example Tutorial - Generic Method, Class ...
To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound, similar like ......
Read more >

github_iconTop Related Medium Post

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