Skip to content

Feature: Extends doesn't constrain a generic typeΒ #47730

Closed

Description

@formula1

Suggestion

πŸ” Search Terms

EventEmitter, extends, generics, nodejs, typescript, keyof, Objects, interface, constraints

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals. (I'm pretty sure)

⭐ Suggestion

Extends doesn't constrain the generic type, it just expects the type to have at least those qualities. I'd like to ensure that only the expected types are allowed. This is useful for things like a typed event emitter that loop over the keys of a generic. As it stands now, I have to get a bit ugly which may open up possible errors.

Having a constrainedby keyword or something similar would allow only generic types or child classes to be subclasses rather than extensions. This would allow child classes to still be considered children of their parents but more strict. However, extensions of the constrained child may try to override the parent so that still needs to be checked.

interface KeyListener {
  [key: string]: Array<0|1>
}

// No errors
class TypedEmitter<C constrainedby KeyListener> extends EventEmitter {
  on<T extends keyof C>(
    event: T, listener: (...args: C[T])=>void
  ){
    super.on(event, listener);
    return this
  }
}

const zero = Symbol("0");
const badInstance = new TypedEmitter<{ [zero]: [0,0,0,0], 1: [1,1,1,1] }>()
/*
    Error, The generic C in TypedEmitter<C> is constrained by KeyListener, only specified keys are allowed
    - [key: string]: Array<0|1>
    Found Bad Keys
    - [symbol("0")]: [0,0,0,0]
    - 1: [1,1,1,1]

*/


interface BadChildInterface constrainedby KeyListener {
  [zero]: [0,0,0,0],
  1: [1,1,1,1] 
  /*
    Error, BadChildInterface is constrained by KeyListener, only specified keys are allowed
    - [key: string]: Array<0|1>
    Found Bad Keys
    - [symbol("0")]: [0,0,0,0]
    - 1: [1,1,1,1]
  */
}

πŸ“ƒ Motivating Example

Playground link with relevant code

Overloading can get absurd

Certianly not DRY

πŸ’» Use Cases

EventEmitters, can't think of much else. But with how common event emitters are, this would be pretty great

Anything that loops over a keyof for type definition

Activity

  1. changed the title [-]Bug: Extends doesn't constrain a generic type[/-] [+]Feature: Extends doesn't constrain a generic type[/+] on Feb 3, 2022
  2. RyanCavanaugh commented on Feb 4, 2022

    @RyanCavanaugh
    Member

    See #14520

  3. formula1 commented on Feb 4, 2022

    @formula1
    Author

    I didn't know what to call it but I like super, at typescript is aware of what people want. Overall, I'm pleased though.

  4. thw0rted commented on Feb 11, 2022

    @thw0rted

    Hi Ryan Cavanaugh (@RyanCavanaugh) , you pointed to #14520 but no one from the team has been active on that issue. Could you please take a look? My post from last year has a lot of positive reaction.

  5. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions