镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

No way to get generic type of an abstract class inside a factory function #35576

Description

TypeScript Version: 3.7.3

Search Terms: abstract class, generic, infer

Code

type InstanceViaNew<T> = T extends { new (...args: never[]): infer R } ? R : never
type InstanceViaProto<T> = T extends { prototype: infer R } ? R : never

function classFactory1<T>() {
  class CS {
    x!: T
  }

  return CS
}

const CSS = classFactory1<string>()
type CS1 = InstanceViaNew<typeof CSS>["x"] // ok, string
type CS2 = InstanceViaProto<typeof CSS>["x"] // not ok, any :(

function classFactory2<T>() {
  abstract class ACS {
    x!: T
  }

  return ACS
}

const ACS = classFactory2<string>()

type AC1 = InstanceViaNew<typeof ACS>["x"] // not ok, never (because abstract classes have no new) :(
type AC2 = InstanceViaProto<typeof ACS>["x"] // not ok, any :(

Expected behavior:

There should be a way to make abstract classes keep the generic information and use it.

Actual behavior:

There's no way to make abstract classes keep the generic information and use it (unless they are type-casted to non abstract classes by adding to them a fake constructor).

Related Issues: #26829

Activity

  1. xaviergonz commented on Dec 9, 2019

    @xaviergonz
    Author

    I have to add that if in classFactory2 the return statement is changed to

    return ACS as typeof ACS & {prototype: typeof ACS }

    Then oddly enough the "InstanceViaNew" works, yet "InstanceViaProto" still doesn't (I'd have expected the opposite)

  2. RyanCavanaugh commented on Jan 22, 2020

    @RyanCavanaugh
    Member

    InstanceViaProto ought to work here; we're probably failing to apply the type mapper in the right place?

  3. xaviergonz commented on Jan 24, 2020

    @xaviergonz
    Author

    Ron Buckton (@rbuckton) I think the PR will certainly make InstanceViaNew work (nice!), but I guess it wouldn't fix the InstanceViaProto case?

  4. xaviergonz commented on Jan 24, 2020

    @xaviergonz
    Author

    Also I found out that if you do something like this:

    function classFactory2<T>() {
      abstract class ACS {
        constructor(_y: number) {}
        x!: T
      }
    
      return ACS
    }
    
    const ACS = classFactory2<string>()
    
    // this doesn't work because the abstract has no constructor (expected I guess)
    type AC3 = InstanceType<typeof ACS>["x"] // Type 'typeof ACS' does not satisfy the constraint 'new (...args: any) => any'
    type AC4 = ConstructorParameters<typeof ACS> // Type 'typeof ACS' does not satisfy the constraint 'new (...args: any) => any'.
    
    // but the intersection of the type with anything makes it somehow work... ?
    // as if the intersection made the class get "unabstracted"
    type AC1 = InstanceType<(typeof ACS) & {whatever: any}>["x"] // weirdly enough this gives string
    type AC2 = ConstructorParameters<(typeof ACS) & {whatever: any}> // weirdly enough this gives [number]
  5. locked as resolved and limited conversation to collaborators on Oct 21, 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

    BugA bug in TypeScript

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions