Typescript: Allow extending types referenced through interfaces

Created on 10 Jun 2019  Â·  6Comments  Â·  Source: microsoft/TypeScript

Suggestion

Allow things like the following:

interface I extends HTMLElementTagNameMap['abbr'] {}

Currently, the following error message is given: "An interface can only extend an identifier/qualified-name with optional type arguments." Which I don't even understand.

I believe it requires no further clarification or justification, but please let me know if that is the case...

In Discussion Suggestion

Most helpful comment

As long as you assign the type a name it works, and it does the proper check already:

interface Bar {}
interface Baz {}

// This doesn't work
interface Foo extends (Bar & Baz) {}

// This works
type _tmp = Bar & Baz;
interface Foo extends _tmp {};

// This fails with a meaningful error message:
// > An interface can only extend an object type or intersection of object types with statically known members. ts(2312)
type _tmp2 = Bar | Baz;
interface Foo extends _tmp2 {};

So IMO we should definitely support the anonymous/expression version of this for orthogonality/consistency

All 6 comments

That error message could definitely be worded better. "An interface can't extend an expression" would probably be clearer (and more concise!).

I don't know about the "qualified-name" part (kind of weird) but "identifier with optional type arguments" basically just means you can either extends Foo or extends Foo<T>. And then if Foo is declared as, like,

interface Foo<T = any>
{
    /* magic goes here */
}

You can just extends Foo again without passing in a type. On the other hand HTMLElementTagNameMap['abbr'], taken as a whole, is not an identifier - it's an identifier with an indexing operator after it, making it an expression. A type-level expression, but an expression nonetheless.

That said, I don't see any theoretical reason why this couldn't work. Might be pretty useful. :+1:

What if the expression is a conditional type?

@AnyhowStep It might be a conditional type hiding behind a type alias right now as well, that works under certain conditions and errors under others. Same rules should apply.

Another point in favor of this is that class C extends <expression>, where the expression evaluates to a constructor at runtime, is legal (one of the reasons why classes aren’t hoisted), so there’s no reason why you shouldn’t be able to do the same with interfaces, at the type level.

In principle it's doable - we can detect when the resolved entity is a legal extends target

As long as you assign the type a name it works, and it does the proper check already:

interface Bar {}
interface Baz {}

// This doesn't work
interface Foo extends (Bar & Baz) {}

// This works
type _tmp = Bar & Baz;
interface Foo extends _tmp {};

// This fails with a meaningful error message:
// > An interface can only extend an object type or intersection of object types with statically known members. ts(2312)
type _tmp2 = Bar | Baz;
interface Foo extends _tmp2 {};

So IMO we should definitely support the anonymous/expression version of this for orthogonality/consistency

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Roam-Cooper picture Roam-Cooper  Â·  3Comments

Antony-Jones picture Antony-Jones  Â·  3Comments

fwanicka picture fwanicka  Â·  3Comments

manekinekko picture manekinekko  Â·  3Comments

blendsdk picture blendsdk  Â·  3Comments