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

Partial classes #563

Closed
disshishkov opened this issue Aug 29, 2014 · 224 comments
Closed

Partial classes #563

disshishkov opened this issue Aug 29, 2014 · 224 comments
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript

Comments

@disshishkov
Copy link

Add support of partial classes. Mixins is not the same, because it's run-time realization. Need compile realization, where partial classes will be combine into one before converting typescript to javascript.

//FileA.ts
partial class ClassA
{      
    constructor(public name: string) {}
    public sayHello(): string { return "hi!"; }
}

//FileB.ts
partial class ClassA
{
   public sayBye(): string { return "by!"; }
}

will be:

partial class ClassA
{      
    constructor(public name: string) {}
    public sayHello(): string { return "hi!"; }
    public sayBye(): string { return "by!"; }
}
@Davidhanson90
Copy link

I think you employ "partial" on modules too and help resolve this issue raised here.

#447

@basarat
Copy link
Contributor

basarat commented Aug 29, 2014

@disshishkov perhaps extension methods be sufficient : #9

@RyanCavanaugh
Copy link
Member

What kind of situations do you want to use this for, and how do existing solutions fall short of that?

Note that this was implemented in C# to support WinForms-type editing scenarios where you have an auto-generated file and a user-edited file contributing to the same type; I'm not sure those kind of situations apply in JavaScript/TypeScript.

@disshishkov
Copy link
Author

Some classes can has many line numbers, just for better read splitting to several separate classes will help. You can split by different type, for example by logic (in case where this logic can not moved to another class), by visibility (private and public) and other. In case when combing of partial classes can has problems (for example 2 partial classes same the same method/variable declaration) compiler should notify and throw error.

@RyanCavanaugh
Copy link
Member

This isn't really compelling. If your class is so large it can't be comfortably edited in a single file due to its sheer size, it's a very major design smell (e.g. comments in http://programmers.stackexchange.com/questions/157482). Splitting by different type/logic/visibility/etc is something that could be handled by an IDE or by organization within a single file.

It's worth discussing why your classes are so big they can't be navigated (is it because the navigation tools should be better?), and if there are better ways the language could support decomposing a class rather than just splitting it.

@rjamesnw
Copy link

rjamesnw commented Sep 2, 2014

Personally, I think "partial classes" should exist, but behave like modules that merge together. I have a system with modules that, although intellisense sees all modules (as it should), the actual JS containing it is only loaded when needed. I think that same would be great for classes as well - to only load the parts needed. I've also wanted to create a function, and use a class to further expand on it. Currently, you can only do this with modules.

@kvantetore
Copy link

A use case for partial classes is for generated proxy classes. E.g. WebAPI or SignalR wrappers. It would be really nice to be able to extend the generated proxy classes with custom logic. Especially when generating classes for models it would be nice to be able to attach business logic directly to the model classes returned from the api.

@wsmckenz
Copy link

+1 kvantetore.

The use case is exactly the same as .net; a portion of the class is generated (in our case, from Avro schemas) and you want to add additional helper code for working with the generated classes.

@yahiko00
Copy link

I like this suggestion. I would like to have partial classes in order to separate attributes/properties of classes forming my "data hierarchy" which could be gathered in one single file, from their methods which can be split in several other files. It would make code clearer and easier to understand in one glance imo.

My data hierarchy file:

class A {
  x: number;
  y: number;
  z: number;
}

class B extends A {
  value: string;
  flag1: boolean;
  flag2: boolean;
}

File containing methods of class A:

class A {
  constructor(x: number, y: number, z: number) {
    this.x = x;
    this.y = y;
    this.z = z;
  }
  method1(...) { ... }
  ...
  methodN(...) { ... }
}

File containing methods of class B:

class B extends A {
  constructor(x: number, y: number, z: number, value: string) {
    super(x, y, z);
    this.value = value;
    this.flag1 = false;
    this.flag2 = false;
  }
  method1(...) { ... }
  ...
  methodN(...) { ... }
}

@jfrank14
Copy link

jfrank14 commented Dec 4, 2014

+1 from me. I would like to use tt templates to generate Typescript classes, but add to them in a separate file that won't get replaced by the template generation.

@chrizy
Copy link

chrizy commented Dec 4, 2014

+1 This will really help me with my auto generated classes that I need to extend

@fletchsod-developer
Copy link

Partial Class is really nice but it doesn't make sense to have it. It showed you have a design problem. Rule of thumb in programming is to keep it simple stupid (KISS), regardless of languages you use, is to break apart large class into smaller ones - by either 1) splitting off scripts into classes and call them (Other classes can also call that smaller classes too instead of re-inventing the wheel), or 2) break apart & convert into Abstract/Interface/Inheritance/Virtual etc. or polymorphism.

Let's say you have a Vehicle with everything in it. A partial class doesn't make sense and it introduce complexity & overhead here where it makes more sense to do this instead. Create an Engine class, Tranny class, Drivetrain class, Door class & Tire class as seperate classes and move scripts over to them, that when called can still define a Vehicle within the Vehicle class. It reduce lengthy scripts & script complexity. Chance are you will find you have Door scripts here and there which can be simplified by a Door class. Interface/Abstract/Inheritance/Virtual can be use to alter the Door class definition on some scripts in the Vehicle class.

You're also more likely to have less develoment time this way. I once had the ASP.NET C# Blog that use lots of partial classes. I had struggled with it cuz of too many partial classes and you don't know where they are. It is sort of like dealing with GOTO logic in programming. Bad bad!! I was never able to create a patch for the bugfix successfully, nor was I able to customize the script cuz it was too buried in pile of partial classes (so do some renamed wording).

Just saying it as a 1 cent thought from my mind.

@jfrank14
Copy link

jfrank14 commented Dec 4, 2014

@fletchsod-developer: Some situations are properly handled by inheritance, but not all. And some developers may misuse partial classes, but not all. There are some situations where I find partial classes very, very useful, but if you don't like them, you don't have to use them.

@NoelAbrahams
Copy link

@jfrank14, as suggested above by @basarat would #9 not work for you?

// File1.ts
class Dog { 
 ...
}

// File2.ts
extends class Dog {
  woof() { /* ... */ }
}

@kvantetore
Copy link

@NoelAbrahams, would you be able to acces the definitions from file1 in file but not vice versa? That's ok for me as long as is independent of inclusion order.

@giancarloa
Copy link

I really hope you guys consider partial classes a la C# for TS... for me the only reason is code generation, which is the primary reason behind C#'s partial classes... we are currently doing a lot of TS code generation, and we expect to be doing more and more... currently we have to rely on "//<code" regions in order to preserve our custom code... it's OK i guess but it's not a universal solution to extending code generated classes... but partial classes are... this way tools can all use the same way of providing extension points to code generated classes... please do expect C#/VB to TS code generation to be a common thing just because it's common to use TS for the client and C#/VB for the server, and it's common, whether good or bad, to want to share code between server and client, at least structure... partial classes would help extend generated code... C# examples all over the place, not just winforms, also EF, RIA, etc...

@starkna
Copy link

starkna commented Mar 9, 2015

+1 - Could really use this for adding functionality to auto-generated classes; no other elegant solution exists that I can think of or have read about to date...

@ghost
Copy link

ghost commented Mar 13, 2015

+1 - Code generated classes. C#/Java objects serialized to client

@JoshMcCullough
Copy link

Need this also for merging of generated classes!

@AndreasPresthammer
Copy link

This would be a very useful feature to allow simple merging of generated code with non-generated code.

@niemyjski
Copy link

+1

@hdachev
Copy link

hdachev commented Apr 26, 2015

+1 - We also need it for partially generated classes, would be more elegant than inheritance which emits quite a bit of code that's not needed for this purpose.

@DmitryEfimenko
Copy link

+1

@JoshMcCullough
Copy link

Ran into this limitation again - please add this feature! 👍

@laszlojakab
Copy link

+1

2 similar comments
@roelvanlisdonk
Copy link

+1

@czlatea
Copy link

czlatea commented Jun 5, 2015

+1

@kitsonk
Copy link
Contributor

kitsonk commented Apr 5, 2017

As an exercise, try to implement the following code split with mixins

So back to the point... So instead of pointing out a language feature, what problem are you trying to address with your example? Because the workaround in TypeScript is easy:

class Point {
  readonly x: number;
  readonly y: number;
  translate(dx: number, dy: number): Point {
    return new Point(this.x + dx, this.y + dy);
  }
}

@kitsonk
Copy link
Contributor

kitsonk commented Apr 5, 2017

(and if we are completist, but again, it solves a use, not all use cases)

interface PointBase {
    x: number;
    y: number;
}

interface Constructor<T> {
    new (...args: any[]): T;
    prototype: T;
}

interface TranslatePointPartial {
    translate(dx: number, dy: number): TranslatePointPartial;
}

function TranslatePointPartial<B extends Constructor<PointBase>>(base: B): B & Constructor<TranslatePointPartial> {
    return class TranslatePointPartial extends base {
        translate(dx: number, dy: number): TranslatePointPartial & PointBase {
            return new TranslatePointPartial(this.x + dx, this.y + dy);
        }
    };
}

class Point {
    readonly x: number;
    readonly y: number;
}

const MyPoint = TranslatePointPartial(Point);

const instance = new MyPoint();

instance.x;
instance.y;
instance.translate(1, 2);

@RyanCavanaugh
Copy link
Member

@Elephant-Vessel

Considering this, would a possible way forward be to clearly distinguish, organizationally and code-wise, between the pure typing of JS, and the other language constructs that TS offers?

I don't see a way to disentangle the two at this point. One could, in theory, write some language ala CoffeeScript that syntactically transformed to TypeScript and use that higher-level language to add new syntactic features while still using TS's type system, but that'd only get you so far. Just picking one of the many other greenfield compile-to-JS languages instead seems like a better choice if that's the goal.

Are you saying that stuff like this aren't going to happen because we should only use modules? Are namespaces on the road to deprecation?

Namespaces aren't going anywhere, for sure. They're just a naming of a pattern that's already in widespread use and they still make plenty of sense in a world of ES6 modules. Modules are just increasingly the way people organize their code and they have a lot of great side benefits. I'm just saying that partial classes make almost no sense in that world, and it'd be odd to add a fundamentally new organizational pattern that's incompatible with it. If the world were moving in the opposite direction and everyone was like "Global scripts with side effects on load are awesome, everyone party on each others' prototypes", maybe we'd feel differently.

@giancarloa
Copy link

@RyanCavanaugh

Perhaps so... Perhaps they don't make as much sense... But like I have said numerous times, I think even in this thread, partial classes are all about making code generation easier... That's the main benefit I see from them worth the feature in TS... I, and I have to assume many others but that's just a guess, am currently generating tons of TS code from my C# code... But then the question becomes how to safely extend the generated TS code??? This is a far easier question to answer with partial classes... Currently we are resorting to hacks in order to keep custom code in our generated TS code files...

Thanks

@RenaudGelai
Copy link

Same thing here, we generate the typescript "proxy" for our C# APIs, and we'd like to be able to extend these objects in typescript easily.

I'm not a JS specialist so i must be missing something, because, i don't see why being able to split the declaration of classes in multiple TS files (with only one class declaration in only one JS file after compilation) would be a problem for the JS world. As far as i see it, it's transparent for JS, as if it would have been written in one file from the begining. I mean, if you use partial classes or not, the JS output will be exactly the same, but it will prevent the cost of JS object extensibility for our developpers.

@giancarloa
Copy link

@RyanCavanaugh

One other thing I wanted to mention that me personally I am not asking the TS compiler to somehow solve the packaging dilemma that might arise when creating an ES6 module using partial classes in different TS files... It makes perfect sense to me at least to compile multiple TS files into a single js file for the ES6 module... Again, partial classes helps code generation significantly... They allow tooling to create large parts of your model with reliable extensibility...

@cosmoKenney
Copy link

cosmoKenney commented Apr 5, 2017

@kitsonk

You keep asking for a specific language feature, as in "I would love a green car" but aren't getting to the crux of the issue, why does the car need to be green? If you explained why your car needs to be green, or be open to the fact that you don't actually care what colour your car is, as long as it provides for your real needs.

No, I'm not asking for a new feature anymore. It has been stated over and over that the language can accomplish what I want. I've provided examples of what I want (in C#), but I have yet to see in the helpful examples a way to get to where I need to be at.

I don't see why you feel it is Ryan's obligation to tell you how to repaint your car, just because for valid reasons the car company has decided not to produce green cars.

Ryan seems to be a moderator here and is closing the issue. That's why. If he is a language authority, then perhaps he shouldn't close the issue before making an effort to understand my need and dismissing this request without providing example of how to do it with native language features. I've stated that I'd like a compile-time solution. And I'm a pretty good developer and have been around for a while programming in many different and obscure languages, and I still have a really hard time with the mixin syntax. I don't get how something that complex and hard to understand got into the language, and yet everyone is rejecting the elegance of partial class syntax, simply, it seems, because it's borrowed from C#.

@RyanCavanaugh
Copy link
Member

Ryan seems to be a moderator here and is closing the issue. That's why. If he is a language authority, then perhaps he shouldn't close the issue before making an effort to understand my need

🤔

@cosmoKenney
Copy link

@RyanCavanaugh, I know you've made an effort to help. And at this point I'm moving on to try mixins. Or just inheritance, or maybe I'm in such a hurry to get this project done that I'm overlooking a way to do this with generics. Hmm...
With inheritance and naming, I can do:

class AddressBase // this is a code generated class
{
	public address: string;
	public city: string;
	public state: string;
	public zip: string;

	constructor( jsonFromService: any )
	{
		this.OnInit( jsonFromService );
	}

	OnInit( jsonFromService: any )
	{
		// could use Object.assign here
		this.address = jsonFromService.address;
		this.city = jsonFromService.city;
		this.state = jsonFromService.state;
		this.zip = jsonFromService.zip;
	}
}

class ContactBase // this is also a code generated class
{
	public firstName: string;
	public lastName: string;

	constructor( jsonFromService: any )
	{
		this.OnInit( jsonFromService );
	}

	OnInit( jsonFromService: any )
	{
		// could use Object.assign here
		this.firstName = jsonFromService.firstName;
		this.lastName = jsonFromService.lastName;
	}
}

// classes that extend the functionality of the code generated classes:
class Address extends AddressBase // subclass simply because I don't want to have to use AddressBase all over my codebase, and then refactor if I ever extend the class
{
}

class Contact extends ContactBase
{
	public Addresses: Address[] = []; // THIS is the customization/extension that cannot be code generated.

	OnInit( jsonFromService: any )
	{
		// note that jsonFromService receives a dto with a array of address info
		super.OnInit( jsonFromService );

		for ( let addr of jsonFromService.Addresses )
		{
			this.Addresses.push( new Address( addr ) );
		}
	}
}

And that works fine for me. It's not as pretty and forces my code generated classes to have names that I don't want to use in code. But, again it works.

@greendimka
Copy link

At the moment I feel that guys, who are strongly against partial classes, simply misuderstand the concept of partial classes, and they think that partial classes are something what partial classes are not.

To make it clear: partial class is a syntactical construction, which lets you split the definition of a same single class into several physical files. Keywords here are "same" and "single".

TypeScript's documentation gives bad definition of partial classes (first paragraph here: https://www.typescriptlang.org/docs/handbook/mixins.html).

Example of real partial classes concept:

File "Point.generated.ts":

partial class Point {
   readonly x: number;
   readonly y: number;
}

File "Point.codeByHand.ts":


partial class Point {
  constructor(x: number, y: number) {
      this.x = x;
      this.y = y;
  }

  translate(dx: number, dy: number): Point 
  {
      return new Point(this.x + dx, this.y + dy);
  }
}

They compile into "Point.js" - and the name comes from the name of a class, not from the names of files:

var Point = (function () {
    function Point(x, y) {
        this.x = x;
        this.y = y;
    }
    Point.prototype.translate = function (dx, dy) {
        return new Point(this.x + dx, this.y + dy);
    };
    return Point;
}());

Mixins, when used as "partial classes" (and I strongly believe that this term in documentation is misused) actually represent a multiple inheritance (https://en.wikipedia.org/wiki/Multiple_inheritance).

So, as we see, we discuss two different tools: real partial classes and multiple inheritance. These are two different tools. And as any tool - they have their own area of application. In other words: a carpenter may use a hammer instead of a mallet, when the mallet is not available, but the hammer is not the right tool.

IMHO, this discussion has no future and we should stop it. While I still see no technological problems for real partial classes, the team really has no wish to implement them, at least for now.

@saschanaz
Copy link
Contributor

saschanaz commented Apr 8, 2017

The TS team does not want to implement TS-specific features if possible. If you do want to discuss more then here is a better place: https://esdiscuss.org/topic/class-syntax-enhancements

I hope there is a GitHub repo on TC39 side to discuss this things rather than mailing based one :/

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Apr 9, 2017

@greendimka

At the moment I feel that guys, who are strongly against partial classes, simply misuderstand the concept of partial classes, and they think that partial classes are something what partial classes are not.

To make it clear: partial class is a syntactical construction, which lets you split the definition of a same single class into several physical files. Keywords here are "same" and "single".

I don't think anyone here is misunderstanding the definition of partial classes, I think you're perhaps misunderstanding the definition of classes in JavaScript.

If you are under the impression that JavaScript classes are at all like the classes found in virtually any other widely used language, then it might well appear to you that others others are misunderstanding.

However, as has been said multiple times in this discussion, I know I've said it explicitly at least once, JavaScript classes are not declarative constructs they are imperative.

They do not exist until statements are executed.

Defining them relies on mutation.

This already makes them brittle and order dependent when it comes to inheritance.

This could go on and on...

@cosmoKenney

I don't get how something that complex and hard to understand got into the language, and yet everyone is rejecting the elegance of partial class syntax, simply, it seems, because it's borrowed from C#.

I really don't think that is correct. Everyone loves C#, even Java programmers 😛, and TypeScript is not different for the sake of being different.

@greendimka
Copy link

greendimka commented Apr 9, 2017

@aluanhaddad

I think you're perhaps misunderstanding the definition of classes in JavaScript...

For citated and below: I am talking about the TypeScript.
As I said: I do not see any technical problem implementing real partial classes in TypeScript, which will be compiled into constructs of JavaScript.

@aluanhaddad
Copy link
Contributor

@greendimka

For citated and below: I am talking about the TypeScript.
As I said: I do not see any technical problem implementing real partial classes in TypeScript, which will be compiled into constructs of JavaScript.

The problem with this satatement there is no such thing as a TypeScript class.

@greendimka
Copy link

Oh, boy! Some people will use anything as a reason.
Ok, there are no classes in TypeScript. Or TypeScript classes. Or whatever. Whatever.

@aluanhaddad
Copy link
Contributor

I mean that they are JavaScript classes. While I am at times guilty of being pedantic, I'm very specifically making this distinction because we need to agree on the definition of the term class before we can discuss what features are simple to add to them.

I think we don't mean the same thing when we speak of classes and that causes cognitive dissonance and impedes mutual understanding.

@greendimka
Copy link

I think we don't mean the same thing when we speak of classes and that causes cognitive dissonance and impedes mutual understanding..
Totally agree!

@greendimka
Copy link

In fact the first post in this topic perfectly describes what was requested, therefore this discussion has no future :)

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Apr 11, 2017

@greendimka yes, it has no future as it seems TypeScript will never have partial classes. In my view, that is a good thing.

However, misunderstandings and miscommunications are not good things which is why I am still conversating with you.

Unfortunately, you do not seem to be interested in either

A. Explaining what JavaScript are classes are that one might might change their mind and come to agree with you that they can trivially be made partializable.

B. Learning from others about what JavaScript classes are so that you must understand the opposing point of view.

I think that this is a shame, but I will not discuss it further if you so wish.

@greendimka
Copy link

I am not against any discussions. But it has been stated several times here that partial classes will not be implemented (at least not now). So I think it is better to concentrate on other things. Maybe TypeScript can be changed in the future, who knows.
In relation to A and B. I hate JavaScript. But I know it very well and, of course, I know how classes are "represented" in it. But the point of this whole discussion was not to modify the JavaScript, but to improve abilities of TypeScript, as a higher language, which produces "low-level" JavaScript code.
Imagine we would replace TypeScript with C++ and JavaScript with machine code. Machine code lacks most concepts which exist in C++. But should C++ stop evolving because of it? Of course no. Should it stop evolving because some old compilers will not be able to compile? Of course no - you give a new feature to developers and tell them: it works with new compilers - you (developers) decide if you want to use it.

@cosmoKenney
Copy link

@aluanhaddad
Man oh man. Who cares about the Javascript part of the equation? TypeScript is a layer above, or however you want to phrase it. Remember the old 4GL vs. 3GL discussions? TypeScript is to Javascript as a 4GL is to a 3GL, kind of. Also the argument that TypeScript is ES6 with strong types, thus Partial Classes is outside the scope of TypeScript's roadmap is LAME. We got Mixins, Generics, Modules, Name Spaces and Type Casting. So why not go the extra mile with Partial Classes?

All we want out of partial classes is the syntactic sugar that enables us to amalgamate all the various definitions of a single TypeScript class into one final - low level - 3GL - Javascript class definition. There should be no impact on the final JavaScript class definition, right? Why is the final product of the transpilation to Javascript even part of this discussion? Seriously.

@spion
Copy link

spion commented Apr 11, 2017

@cosmoKenney "its just ES.next with types" is a big selling point that converts JavaScript developers. If you want something more, you're looking at the wrong language. Maybe try Scala.js instead?

edit: I just had an interesting realisation that in ES.next partial classes can be implemented with a custom module loader. If you use

import {MyClass} from './myclass.*'

the loader could merge all exported MyClass definitions from any files matching the wildcard into a single class, then provide that.

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Apr 11, 2017

@spion I like how you are quite correctly referring to them as ES.next partial classes. An ES module loader, such as a browser, or loader polyfill, such as SystemJS, would then support partial classes.
One of the primary problems with adding this feature at the TypeScript level is that it breaks existing tools such as loaders and packagers. On the other hand, if ECMAScript specified them, then all of these tools would implement the feature and TypeScript would remain compatible with all of these tools.

I definitely agree with you regarding Scala.js

@cosmoKenney

We got Mixins, Generics, Modules, Name Spaces and Type Casting. So why not go the extra mile with Partial Classes?

Mixins as seen in TypeScript are an ECMAScript design pattern that TypeScript types.

Generics are a type system feature so they do not apply.

Modules are an ECMAScript feature.

Namespaces are a syntactic sugar for and a formalization of an ECMAScript design pattern.

Type Casting does not exist in TypeScript.

@cosmoKenney
Copy link

@aluanhaddad why do you keep making this out as a run-time thing? Module loaders and all that have nothing to do with transpiling.

@winuxue
Copy link

winuxue commented Apr 25, 2017

+1

@aluanhaddad
Copy link
Contributor

@cosmoKenney

@aluanhaddad why do you keep making this out as a run-time thing? Module loaders and all that have nothing to do with transpiling.

That is not correct.

Look at the SystemJS and Webpack ecosystems and you will see otherwise.

Even more traditional, and rock solid gulp workflows rely on the correspondence between input and output files.

@jeeshenlee
Copy link

+1

I need partial class because we are generating most of the base class using tools (to automate when there's a changes in the model). We then use partial class to add functionality to the class in a separate files so it won't be overwrite by the tool (that auto-generate the class).

@microsoft microsoft locked and limited conversation to collaborators May 10, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Out of Scope This idea sits outside of the TypeScript language design constraints Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests