Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

180
Views
Strange behaivour of TypeScript when extending class with similar namespace structure

Recently I've been trying to create a type library for library written in JS. When I declared all namespaces, classes and interfaces, some classes started to give me an error TS2417. I checked if there was any problem with invalid overriding of methods or properties, but I couldn't find anything. After some time I've found that the problematic class had same name as one of the namespaces (for example class A.B and namespace A.B). But this didn't cause any trouble. The problem was that the parent class (of the problematic class) had, just as the problematic class, namespace which was named exactly the same and this namespace and the namespace of the problematic class had class, which was named exactly the same, but had different interface (it is very hard for me to describe the problem, so I simulated here).

So the question is, what causes this problem?

In this example the problematic class is A.C, but it has problems due to incompatible constructors of classes A.C.X and A.B.X.

declare namespace A {
  class B {

  }

  namespace B {
    class X {

    }
  }

  class C extends A.B {

  }

  namespace C {
    class X {
      constructor(x: number)
    }
  }
}
about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

(In the following I will dispense with the namespace A)

With the exception of the construct signature, the static side of a class is checked for substitutability the same way that the instance side is; so if you have class X { static prop: string = "" }, then you can't have class Y extends X { static prop: number = 2}. When you say class Y extends X you are declaring that, among other things, Y.prop is assignable to X.prop. See microsoft/TypeScript#4628 for more information. Not everyone likes this constraint, but it's there.


That means the following should work with no error:

const X: typeof B.X = C.X; // should be okay
new X(); // should be okay

But a concrete implementation of your classes could easily lead to a runtime error:

class B {
  static X = class { }
}

class C extends B {
  static X = class {
    constructor(x: number) {
      x.toFixed();
    }
  }
}

Here, C.X is a class constructor which requires a number input. But B.X is a class constructor which does not require any input at all. And if you treat the former as if it were the latter, than at runtime you will be calling the toFixed() method on undefined. Oops.

And that's why class C extends B generates a compiler error; to protect you against substitutability issues arising from the static side of a class.

Playground link to code

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!