microsoft / microsoft/TypeScript

Abstract property specified on multiple classes loses modifier after intersection

Open
#56,738 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Domain: Intersection Help Wanted
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
1d 19h
Merged PRs (30d)
117

Description

🔎 Search Terms

abstract property class intersection InstanceType typeof mixin trait

🕗 Version & Regression Information
  • This is the behavior in every version I tried
⏯ Playground Link

https://tsplay.dev/mAL7ZN

💻 Code
abstract class A {
	abstract a(): number
}

abstract class A2 {
	abstract a(): number
}

abstract class B  {
	abstract b(): number
}

declare const Base: abstract new () => A & B

// correctly has type error requiring the implementation of 'a' and 'b'
class Foo extends Base {}

declare const FalsePositiveBase: abstract new () => A & A2

// this sould be an error
// if an abstract property appears on multiple classes, it is not treated as abstract
class Bar extends FalsePositiveBase {}

Seems like there must be some flag that associates the abstractness of the original class instance when it is used as a class instance like that, but there is a logic error that checks if the prop exists on other intersection members and erases the modifier, even if all of them are also abstract.

I previously thought this was a workaround:


// can workaround this as follows:
declare const WorkaroundBase: abstract new () => InstanceType<typeof A & typeof A2>

// now gives the correct error that 'a' is missing
class Baz extends WorkaroundBase {}

But realized that it is just treating the constructor as an overload and only using one of the instance types.

🙁 Actual behavior

Behavior for multiple props of the same name was inconsistent with behavior for props with differing names

🙂 Expected behavior

Intersecting multiple props of the same name that all of the abstract modifier should preserve it

Additional information about the issue

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked TypeScript Playground and reproduce the difference between Foo and Bar using intersections of abstract classes. Trace how the type checker handles the shared abstract member during class extension, then verify that the expected error for Bar is preserved without relying on the workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.