Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support abstract class methods without abstract class #57940

Closed
6 tasks done
Irrelon opened this issue Mar 25, 2024 · 2 comments
Closed
6 tasks done

Support abstract class methods without abstract class #57940

Irrelon opened this issue Mar 25, 2024 · 2 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@Irrelon
Copy link

Irrelon commented Mar 25, 2024

πŸ” Search Terms

abstract methods runtime prototype typesafe synthesized

βœ… Viability Checklist

⭐ Suggestion

It would be good if we could declare a method as abstract without the requirement to declare the entire class as abstract.

πŸ“ƒ Motivating Example

Take an example class such as:

class MyClass {
    protected _id?: string;
    protected _isVisible?: boolean;

    id (val?: string): string | this | undefined {
        if (val === undefined) {
            return this._id;
        }

        this._id = val;
        return this;
    }

    // Similar implementation for isVisible()
}

If I have a bunch of accessor functions like id() that follow the same getter/setter behaviour I have to write out each one in concrete code which takes time and wastes bytes across the network when the code gets sent down the pipe.

What I would do in JS is create a synthesize() function that takes the class and the method name and then generates the function at runtime against the underlying prototype, something like:

function synthesize<FunctionArgType = any> (Class: any, methodName: string) {
	const privatePropertyName = `_${methodName}`;

	Class.prototype[methodName] = function (val?: FunctionArgType) {
		if (val === undefined) {
			return this[privatePropertyName];
		}

		this[privatePropertyName] = val;
		return this;
	};
}

It then becomes trivial to add the desired methods as:

synthesize(MyClass, "id");
synthesize(MyClass, "isVisible");
// ...etc etc

At present, I can "sort of" achieve this by ts-ignoring the abstract methods that I know are going to become available at runtime:

class MyClass {
    // @ts-ignore
    abstract id (val?: string): string | this;
    // @ts-ignore
    abstract isVisible (val?: boolean): boolean | this;
}

This is a bit sad given that the JS functionality can significantly reduce the byte-size of the file if the class is large and provides a lot of similar accessor functionality. I realise that this might appear to be an edge-case, but right now, TS makes writing conforming JS of this nature a real burden by either creating concrete classes, or ts-ignoring like it's 1999.

πŸ’» Use Cases

  1. What do you want to use this for?
  2. What shortcomings exist with current approaches?
  3. What workarounds are you using in the meantime?
@RyanCavanaugh
Copy link
Member

Just use interface merging?

class MyClass {
  // etc
}
interface MyClass {
  isVisible():  boolean;
}
const c = new MyClass();
console.log(c.isVisible()); // ok

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Mar 28, 2024
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Question" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Mar 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants