question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Methods are not accepted as implementation of abstract members with function type

See original GitHub issue

Bug Report

I am declaring a named type with the signature for an abstract method(ish)* on a base class. But I am not able to use the Signature type directly to declare the method, instead I need to pluck off Parameters<Sig> and ReturnType<Sig> to declare a “real” method. Given how methods usually behave in TS interfaces, this is certainly surprising.

  • To expand on the motivation for doing this: The real-world use case involves a “pluggable” method where some subclasses have a call method that implements the interface, and others do constructor(public readonly call: Sig, ...otherArgs) so that they have an injectable call member. In either case, the consumer of the api just does myObj.call(blah, blah, blah) and it Does The Right Thing. I am declaring the named Sig to avoid repeating it everywhere.

🔎 Search Terms

abstract method member function TS2425

🕗 Version & Regression Information

When did you start seeing this bug occur?

Repros in oldest and nightly in playground.

This is the behavior in every version I tried, and I reviewed the FAQ for entries about _________

“Bugs” that have existed in TS for a long time are very likely to be FAQs; refer to https://github.com/Microsoft/TypeScript/wiki/FAQ#common-bugs-that-arent-bugs

I’ll admit this is certainly similar to the third from the last issue in that list:

  • A method and a function property of the same type behave differently.
    • Methods are always bivariant in their argument, while function properties are contravariant in their argument under strictFunctionTypes. More discussion here.

However, that summary and the linked issue are all about bivariance/invariance/contravariance which controls matching semantics for functions with different signatures. In this case, the signatures are identical, so that difference doesn’t apply. This appears to be a different difference (at least to me). If this is intentional, perhaps the FAQ should be updated to focus less on variance. Ideally, explaining why even identical signatures are rejected.

Issue #27965 also seems related, but that case is a bit different. It was declaring an actual member, which may exist in JS land on the base, while this issue is specifically about adding an abstract member, which I would expect to be more like adding something to the interface portion of a class type, since it explicitly isn’t set by the base in JS. Also that case tried to use any as the “function” type of the member, and I am using an exact-matching function type.

⏯ Playground Link

Playground link with relevant code

💻 Code

type Sig = (n: number) => number

abstract class Base {
    abstract member: Sig;
    abstract method(...args: Parameters<Sig>): ReturnType<Sig> // This works, but is something only a type theorist would love.
}

class DerivedMethods extends Base {
    member(n: number) { return n; } // <---- Error here ☹
    method(n: number) { return n; }
}

class DerivedMembers extends Base {
    member!: Sig;
    method!: Sig; // Note: this works in the opposite direction!
}

🙁 Actual behavior

Class ‘Base’ defines instance member property ‘member’, but extended class ‘DerivedMethods’ defines it as instance member function.

🙂 Expected behavior

Compile without error

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
RyanCavanaughcommented, Oct 21, 2022

I don’t think we need to enforce this rule for abstract members – it doesn’t really make any sense.

1reaction
RyanCavanaughcommented, Oct 24, 2022

It wouldn’t compile. Method bivariance is determined by the target type, not the source type (I had to look this up). You can try it today and see that that error, along with the one about methodness/propertyness, are both issued.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Abstract Methods and Classes (The Java™ Tutorials ...
Abstract classes cannot be instantiated, but they can be subclassed. An abstract method is a method that is declared without an implementation (without ......
Read more >
`static abstract` methods and properties · Issue #34516 - GitHub
I think I have to pass separate instance-type and class-type generic parameters, since I'm not hard-coding "YourClass" as in your example. I ...
Read more >
TS Abstract method implementation can define any element of ...
All implementations of Abstract must have a method that takes a single ( string parameter) or ( number parameter). This interpretation means ...
Read more >
Can we define an abstract class with no abstract methods in ...
Yes, we can declare an abstract class with no abstract methods in Java. An abstract class means that hiding the implementation and showing ......
Read more >
Methods - F# | Microsoft Learn
A method is a function that is associated with a type. In object-oriented programming, methods are used to expose and implement the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found