microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.17k stars 12.51k forks source link

Partial classes #563

Closed disshishkov closed 7 years ago

disshishkov commented 10 years ago

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 commented 10 years ago

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

https://github.com/Microsoft/TypeScript/issues/447

basarat commented 10 years ago

@disshishkov perhaps extension methods be sufficient : #9

RyanCavanaugh commented 10 years ago

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 commented 10 years ago

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 commented 10 years ago

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 commented 10 years ago

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 commented 10 years ago

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 commented 10 years ago

+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 commented 10 years ago

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 commented 9 years ago

+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 commented 9 years ago

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

fletchsod-developer commented 9 years ago

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 commented 9 years ago

@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 commented 9 years ago

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

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

// File2.ts
extends class Dog {
  woof() { /* ... */ }
}
kvantetore commented 9 years ago

@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 commented 9 years ago

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 commented 9 years ago

+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...

carltierney commented 9 years ago

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

JoshMcCullough commented 9 years ago

Need this also for merging of generated classes!

AndreasPresthammer commented 9 years ago

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

niemyjski commented 9 years ago

+1

hdachev commented 9 years ago

+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 commented 9 years ago

+1

JoshMcCullough commented 9 years ago

Ran into this limitation again - please add this feature! :+1:

laszlojakab commented 9 years ago

+1

roelvanlisdonk commented 9 years ago

+1

czlatea commented 9 years ago

+1

muzuiget commented 9 years ago

+1

kitsonk commented 9 years ago

People randomly +1 this isn't going to move it on.

The use cases so far are:

The second and third use case is not compelling and the fourth, I suspect needs some level of expounding how delivering #9 wouldn't meet a very similar requirement and even Decorators (#2249).

jfrank14 commented 9 years ago

It does look like #9 would accomplish the same thing and be even more general (because you could extend classes other than your own). But it might be reasonable to want class content in two files (perhaps because one is hand written and the other generated by a template), and to say that both files define the essential members of the class with equal importance, and not require that one file "extend" the class define in the other.

It's an almost existential difference, but perhaps important to some people in some situations.

Davidhanson90 commented 9 years ago

I don't want partial on classes for reasons stated, but on modules it makes sense IMHO.

https://github.com/Microsoft/TypeScript/issues/447

ghost commented 9 years ago

Partial classes are extremely useful for specializing use-cases. It is not a violation of any OOP pattern but a way to arrange code document, which provides:

  1. Ability to split the class/type definition in multiple files. For huge code files, it is maintainability++ feature.
  2. Opportunity for compiler/build-system to make use of conditional linkage at compile-time. Analogy MSBuild, concrete use-case in C#: DBML, designer classes and even more fancy stuff like https://github.com/dotnet/corefx/pull/2045/files.
  3. Inherent protection, so two (or more) developers don't run into each other during code check-in. Conflict resolution blows! :)
  4. Let you generate code into the main partial class, then create another partial for custom overloads. Works perfectly!

I believe in separating business logic and data layers into separate classes and I mostly use static methods in these layers. I really don't see how it could be more code and less maintainable.

While extension method is a core language feature influenced by OO patterns and will be processed at compile-time, partial classes deals with document/code-layout to be stitched at pre-compilation stage. Despite the similarities in partial classes, abstract classes and extension methods, there is a clear distinction.

:+1: for bringing the harmless "Partial Classes" to TypeScript.

RandScullard commented 9 years ago

My use case for partial classes is for code generation -- my team needs to be able to auto-generate part of the class in one file and add custom methods and properties by hand in another file. I'm a bit confused why @RyanCavanaugh is "not sure those kind of situations apply in JavaScript/TypeScript", since this use case is unrelated to the language of choice.

Neither decorators nor extension methods solve the code generation problem as elegantly as partial classes, and each has substantial additional complexities.

WangJi commented 9 years ago

+1

kobezzza commented 9 years ago

+1

junkyjack1 commented 9 years ago

+1 for code generation purposes.

TylerBrinkley commented 9 years ago

In the C# environment, the integration of a transpiler of C# classes to TypeScript classes would remove the need to keep two different definitions of classes between the server and client side as the client side, aka TypeScript class, would be automatically generated and the partial class that this issue is requesting would allow customization when needed while still developing in native TypeScript.

orellabac commented 9 years ago

+1 for code generation scenarios

greendimka commented 9 years ago

+1 extremely helpful for code generation

spion commented 9 years ago

Why not use inheritance for code generation?

JoshMcCullough commented 9 years ago

Inheritance is messier and has more overhead.

On Mon, Aug 10, 2015, 10:09 AM Gorgi Kosev notifications@github.com wrote:

Why not use inheritance for code generation?

— Reply to this email directly or view it on GitHub https://github.com/Microsoft/TypeScript/issues/563#issuecomment-129468291 .

yahiko00 commented 9 years ago

​Inheritance creates useless name couplings

hdachev commented 9 years ago

Inheritance is less awesome because it:

  1. Deepens the prototype chain needlessly and slows down instantiation, although thats not a big deal for most apps, likely everything but games;
  2. For lack of abstract and override either loses some type safety or introduces the need for some ackward patterns like casting between the two types;
  3. Is confusing overall as having a base class communicates the idea that it can be extended by other classes, which is rarely the case with codegen

Not saying typescript HAS to have partial classes to support codegen, only that partial classes are so much better at it than inheritance or composition.

spion commented 9 years ago

@JoshMcCullough Inheritance overhead in JS is minimal, and I don't see how its messier than partial classes: with those you can potentially split a class into 10 files and chase your methods all over the place.

@yahiko00 What kind of "useless name coupling" are we talking about here? Do you refer to the things you'd need to do to get No. 2 below (hardcoding the name of the extended class)?

@hdachev

  1. There is some overhead, but its quite minimal - only noticeable if you're doing things that translate directly to a couple of machine instructions
  2. Good point - you don't get the extended class when you have to reference the generated class from other generated classes.
  3. Those classes are indeed meant to be extended - otherwise you could generate them and be done with it, right?

AFAIK this is not on the ES7+ radar, is it? That might be problematic...

In any case, attaching extra things to the prototype of an existing class is quite trivial in JavaScript and not at all uncommon, so it might be a good idea to have syntax for that...

JoshMcCullough commented 9 years ago

It's straightforward in TS but the JS behind the scenes would double the "protoyping" if you were using base classes for all of your generated data objects. Probably not a serious performance impact unless you have a ton of data objects, but it still is unnecessary when we know that "partial classes" are possible.

On Mon, Aug 10, 2015 at 11:03 AM Gorgi Kosev notifications@github.com wrote:

@JoshMcCullough https://github.com/JoshMcCullough Inheritance overhead in JS is minimal, and I don't see how its messier than partial classes: with those you can potentially split a class into 10 files and chase your methods all over the place.

@yahiko00 https://github.com/yahiko00 What kind of "useless name coupling" are we talking about here? Do you refer to the things you'd need to do to get No. 2 below (hardcode the name of the extended class)?

class MyClass extends GeneratedMyClass { ... }

@hdachev https://github.com/hdachev

1.

There is some overhead, but its quite minimal https://jsperf.com/prototype-chain-vs-direct-calls - only noticeable if you're doing things that translate directly to a couple of machine instructions 2.

Good point - you don't get the extended class when you have to reference the generated class from other generated classes. 3.

Those classes are indeed meant to be extended - otherwise you could generate them and be done with it, right?

AFAIK this is not on the ES7+ radar, is it?

In any case, attaching extra things to the prototype of an existing class is quite trivial in JavaScript and not at all uncommon, so it might be a good idea to have syntax for that...

— Reply to this email directly or view it on GitHub https://github.com/Microsoft/TypeScript/issues/563#issuecomment-129483174 .

RyanCavanaugh commented 9 years ago

@Davidhanson90 that file has zero classes in it. Did you mean to post this in a different thread?

Davidhanson90 commented 9 years ago

I'll post onto the correct thread. https://github.com/Microsoft/TypeScript/issues/447

kirilpopov commented 9 years ago

+1

do34 commented 9 years ago

+1

Mike-Loffland commented 9 years ago

+100