I want to be able to make the implementation optional for abstract member, but it seems like it is not doable today.
abstract class Component {
public abstract setText?(l: GetLocalization): void;
public abstract bindInteractions?(): void;
}
I have some component classes and they MUST extend the base component class and optionally implement certain methods with a certain signature. Right now, I can only rely on good documentation.
class Post extends Component {
public setText(l: GetLocalization): void {
//...
}
// Though I don't want to implement bindInteractions method.
}
I want the power of auto-completion to also kick in.
It is useful for classes with life cycle methods.
What would be an observable difference between optional and abstract optional?
you can do this today with class an interface merging:
interface Component {
optionalMethod?(l: GetLocalization): void;
}
abstract class Component {
public abstract mustImplement(): void;
}
class Post extends Component {
public mustImplement(): void {
if (this.optionalMethod) {
// do something
}
}
}
@mhegazy your trick seem to have solve my issue.
Though I think defining members and having some of them on a interface declaration and some of them in the class declaration is quite confusing. Besides there is some life-cycle methods that I don't want to expose publicly. I guess your solution only works with public members?
What would be an observable difference between optional and abstract optional?
I guess this could be said with non-optionals as well? I guess the noticeable difference is that, access modifier can be set to private and protected.
looking at the original post again, i do not think abstract
makes sense here. marking a method as abstract
says it is impossible to instantiate this class without implementing this method. if it is optional, i.e. the class can work just fine without instantiating the class. so what you need is either 1. do not mark it as abstract
and give it some default implementation, or 2. declare it as a property and do not mark it as abstract
either.
I think I'm fine with empty body methods if abstract
cannot be optional.
Little bit OT, is there a reason you don't autocomplete methods on an extended class?
@mhegazy Currently TypeScript supports marking an abstract as optional but does not allow concrete classes to omit the implementation, this looks weird to me:
abstract class Foo {
abstract foo?(): void;
}
class Bar extends Foo {
// ERROR: Non-abstract class 'Bar' does not implement inherited abstract member 'foo' from class 'Foo'.
}
And an abstract method, though optional, could suggest the user that "you may want to try out implementing this", instead of "what can I do, I've implemented all those abstract methods, but I still need some tweaks over there".
With interface/class merging, the types of the optional function are not inferred:
interface Component<T> {
optionalMethod?(l: T): void;
}
abstract class Component<T> {
public abstract mustImplement(): void;
}
class Impl extends Component<Props> {
mustImplement() {
// do nothing
}
optionalMethod(p) {
// error TS7006: Parameter 'p' implicitly has an 'any' type.
}
}
shouldn't p type be inferred here?
abstract class Component {
optionalMethod?(l: GetLocalization): void;
public abstract mustImplement(): void;
}
class Post extends Component {
public mustImplement(): void {
if (this.optionalMethod) {
// do something
}
}
}
I just do not use abstract
right now.
If abstract
overrides the ?
-optionality (which IMO it shouldn't), can we at least make abstract method?();
be a syntax error or warning that the ?
does nothing, and it should be made non-abstract or moved into a merged interface instead?
@valotas Parameter types of subclass methods don't ever appear to be inferred:
class Parent {
optionalMethod?(s: string): void;
}
class Child extends Parent {
optionalMethod(s) {
s // (parameter) s: any
}
}
abstract class AbstractParent {
abstract abstractMethod(s: string): void;
}
class ConcreteChild extends AbstractParent {
abstractMethod(s) {
s // (parameter) s: any
}
}
interface Iface {
method(s: string): void;
}
class Klass implements Iface {
method(s) {
s // (parameter) s: any
}
}
So I don't think that's because of the interface/class merging.
What helped for me is just to make them optional (?
) but without abstract
. And without body:
E.g.
export abstract class SyncRemoteConnector<TS> {
upload?(syncable: TS): Observable<any>
downloadAll?(): Observable<Array<TS>>
}
Most helpful comment
you can do this today with class an interface merging: