Typescript: Teilklassen

Erstellt am 29. Aug. 2014  ·  224Kommentare  ·  Quelle: microsoft/TypeScript

Unterstützung von Teilklassen hinzufügen. Mixins ist nicht dasselbe, da es sich um eine Laufzeitrealisierung handelt. Benötigen Sie eine Kompilierungsrealisierung, bei der Teilklassen zu einer kombiniert werden, bevor Typskript in Javascript konvertiert wird.

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

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

wird sein:

partial class ClassA
{      
    constructor(public name: string) {}
    public sayHello(): string { return "hi!"; }
    public sayBye(): string { return "by!"; }
}
Out of Scope Suggestion

Hilfreichster Kommentar

Ein Anwendungsfall für partielle Klassen sind generierte Proxy-Klassen. ZB WebAPI- oder SignalR-Wrapper. Es wäre wirklich schön, die generierten Proxy-Klassen mit benutzerdefinierter Logik erweitern zu können. Besonders beim Generieren von Klassen für Modelle wäre es schön, Geschäftslogik direkt an die von der API zurückgegebenen Modellklassen anhängen zu können.

Alle 224 Kommentare

Ich denke, Sie verwenden "teilweise" auch bei Modulen und helfen, dieses hier angesprochene Problem zu lösen.

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

@disshishkov vielleicht

Für welche Situationen möchten Sie dies verwenden, und inwiefern reichen bestehende Lösungen nicht aus?

Beachten Sie, dass dies in C# implementiert wurde, um Bearbeitungsszenarien vom Typ WinForms zu unterstützen, in denen Sie eine automatisch generierte Datei und eine vom Benutzer bearbeitete Datei haben, die zu demselben Typ beitragen. Ich bin mir nicht sicher, ob diese Situationen in JavaScript/TypeScript zutreffen.

Einige Klassen können viele Zeilennummern haben, nur zur besseren Lesbarkeit hilft die Aufteilung auf mehrere separate Klassen. Sie können nach verschiedenen Typen aufteilen, zum Beispiel nach Logik (falls diese Logik nicht in eine andere Klasse verschoben werden kann), nach Sichtbarkeit (privat und öffentlich) und andere. Falls beim Kämmen von Teilklassen Probleme auftreten können (z. B. 2 Teilklassen gleich die gleiche Methode/Variablen-Deklaration), sollte der Compiler einen Fehler melden und ausgeben.

Das ist nicht wirklich zwingend. Wenn Ihre Klasse so groß ist, dass sie aufgrund ihrer schieren Größe nicht bequem in einer einzigen Datei bearbeitet werden kann, ist dies ein sehr großer Designgeruch (zB Kommentare in http://programmers.stackexchange.com/questions/157482). Das Aufteilen nach verschiedenen Typen/Logik/Sichtbarkeit/usw. kann von einer IDE oder von einer Organisation innerhalb einer einzelnen Datei gehandhabt werden.

Es lohnt sich zu diskutieren, warum Ihre Klassen so groß sind, dass sie nicht navigiert werden können (weil die Navigationswerkzeuge besser sein sollten?)

Persönlich denke ich, dass "partielle Klassen" existieren sollten, sich aber wie Module verhalten, die miteinander verschmelzen. Ich habe ein System mit Modulen, das, obwohl Intellisense alle Module sieht (wie es sollte), das eigentliche JS, das es enthält, nur bei Bedarf geladen wird. Ich denke, das wäre auch toll für den Unterricht - nur die benötigten Teile zu laden. Ich wollte auch eine Funktion erstellen und eine Klasse verwenden, um sie weiter zu erweitern. Derzeit ist dies nur mit Modulen möglich.

Ein Anwendungsfall für partielle Klassen sind generierte Proxy-Klassen. ZB WebAPI- oder SignalR-Wrapper. Es wäre wirklich schön, die generierten Proxy-Klassen mit benutzerdefinierter Logik erweitern zu können. Besonders beim Generieren von Klassen für Modelle wäre es schön, Geschäftslogik direkt an die von der API zurückgegebenen Modellklassen anhängen zu können.

+1 Kvantetor.

Der Anwendungsfall ist genau der gleiche wie bei .net; ein Teil der Klasse wird generiert (in unserem Fall aus Avro-Schemas) und Sie möchten zusätzlichen Hilfscode für die Arbeit mit den generierten Klassen hinzufügen.

Ich mag diesen Vorschlag. Ich möchte Teilklassen haben, um Attribute/Eigenschaften von Klassen, die meine "Datenhierarchie" bilden und in einer einzigen Datei gesammelt werden könnten, von ihren Methoden, die in mehrere andere Dateien aufgeteilt werden können, zu trennen. Es würde den Code auf einen Blick klarer und leichter verständlich machen.

Meine Datenhierarchiedatei :

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

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

Datei mit Methoden der Klasse A :

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

Datei mit Methoden der Klasse 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(...) { ... }
}

+1 von mir. Ich möchte tt-Vorlagen verwenden, um Typescript-Klassen zu generieren, aber in einer separaten Datei hinzufügen, die nicht durch die Vorlagengenerierung ersetzt wird.

+1 Dies wird mir wirklich bei meinen automatisch generierten Klassen helfen, die ich erweitern muss

Partial Class ist wirklich schön, aber es macht keinen Sinn, sie zu haben. Es hat gezeigt, dass Sie ein Designproblem haben. Die Faustregel beim Programmieren ist, es einfach dumm zu halten (KISS), unabhängig von den verwendeten Sprachen, besteht darin, große Klassen in kleinere aufzuteilen - entweder 1) Skripte in Klassen aufteilen und sie aufrufen (andere Klassen können das auch nennen auch kleinere Klassen, anstatt das Rad neu zu erfinden) oder 2) auseinander zu brechen und in Abstrakt/Schnittstelle/Vererbung/Virtuell etc. oder Polymorphismus umzuwandeln.

Nehmen wir an, Sie haben ein Fahrzeug mit allem drin. Eine partielle Klasse macht keinen Sinn und führt hier zu Komplexität und Overhead, wo es sinnvoller ist, dies stattdessen zu tun. Erstellen Sie eine Engine-Klasse, eine Tranny-Klasse, eine Drivetrain-Klasse, eine Tür-Klasse und eine Reifenklasse als separate Klassen und verschieben Sie Skripte dorthin, die beim Aufrufen immer noch ein Fahrzeug innerhalb der Fahrzeugklasse definieren können. Es reduziert langwierige Skripte und Skriptkomplexität. Es besteht die Möglichkeit, dass Sie hier und da Door-Skripte haben, die durch eine Door-Klasse vereinfacht werden können. Interface/Abstract/Inheritance/Virtual kann verwendet werden, um die Definition der Door-Klasse in einigen Skripten in der Vehicle-Klasse zu ändern.

Auf diese Weise haben Sie auch eher weniger Entwicklungszeit. Ich hatte einmal den ASP.NET C#-Blog, der viele Teilklassen verwendet. Ich hatte damit zu kämpfen, weil es zu viele Teilklassen gab und Sie nicht wissen, wo sie sind. Es ist so, als würde man sich in der Programmierung mit der GOTO-Logik befassen. Schlecht schlecht!! Ich war nie in der Lage, einen Patch für den Bugfix erfolgreich zu erstellen, noch konnte ich das Skript anpassen, da es zu in einem Haufen von Teilklassen vergraben war (so wie einige umbenannte Formulierungen).

Ich sage es nur als 1-Cent-Gedanke aus meinem Kopf.

@fletchsod-developer: Einige Situationen werden durch Vererbung richtig gehandhabt, aber nicht alle. Und einige Entwickler können Teilklassen missbrauchen, aber nicht alle. Es gibt Situationen, in denen ich Teilklassen sehr, sehr nützlich finde, aber wenn sie Ihnen nicht gefallen, müssen Sie sie nicht verwenden.

@jfrank14 , wie oben von @basarat vorgeschlagen, würde #9 für Sie nicht funktionieren?

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

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

@NoelAbrahams ,

Ich hoffe wirklich, dass Sie partielle Klassen a la C# für TS betrachten ... für mich ist der einzige Grund die Codegenerierung, die der Hauptgrund für die partiellen Klassen von C# ist ... wir machen derzeit viel TS-Codegenerierung, und wir erwarten, immer mehr zu tun ... derzeit müssen wir uns auf "//

+1 - Könnte dies wirklich zum Hinzufügen von Funktionen zu automatisch generierten Klassen verwenden; Es gibt keine andere elegante Lösung, die mir einfällt oder bis heute gelesen habe...

+1 - Codegenerierte Klassen. C#/Java-Objekte, die für den Client serialisiert werden

Benötigen Sie dies auch zum Zusammenführen von generierten Klassen!

Dies wäre eine sehr nützliche Funktion, um ein einfaches Zusammenführen von generiertem Code mit nicht generiertem Code zu ermöglichen.

+1

+1 - Wir brauchen es auch für teilweise generierte Klassen, wäre eleganter als die Vererbung, die ziemlich viel Code ausgibt, der für diesen Zweck nicht benötigt wird.

+1

Wieder auf diese Einschränkung gestoßen - bitte fügen Sie diese Funktion hinzu! :+1:

+1

+1

+1

+1

Leute geben zufällig +1, das wird nicht weitergehen.

Bisherige Anwendungsfälle sind:

  • Ich habe wirklich große Klassen, die mehrere Dateien umfassen. @RyanCavanaugh wies darauf hin, dass es sich wahrscheinlich um ein großes Designproblem mit Code handelt, der so komplex ist und nicht ausreicht, um die Komplexität der Implementierung zu rechtfertigen.
  • Es gefällt ihnen.
  • Ein weiteres Argument scheint zu sein, dass C# sie hat.
  • Das andere Argument bezieht sich auf generierten Code aus anderen Sprachen.

Der zweite und dritte Anwendungsfall sind nicht zwingend, und der vierte, vermute ich, muss in gewisser Weise erläutert werden, dass die Bereitstellung von Nr. 9 eine sehr ähnliche Anforderung und sogar Dekorateure (Nr. 2249) nicht erfüllen würde.

Es sieht so aus, als würde # 9 dasselbe erreichen und noch allgemeiner sein (weil Sie andere Klassen als Ihre eigenen erweitern könnten). Aber es könnte sinnvoll sein, den Klasseninhalt in zwei Dateien zu haben (vielleicht weil eine von Hand geschrieben und die andere von einer Vorlage generiert wurde) und zu sagen, dass beide Dateien die wesentlichen Elemente der Klasse mit gleicher Bedeutung definieren und dies nicht erfordern Datei "erweitern" die Klasse in der anderen definieren.

Es ist ein fast existentieller Unterschied, aber vielleicht für manche Leute in manchen Situationen wichtig.

Ich möchte aus den genannten Gründen keinen Teil des Unterrichts, aber bei Modulen macht es IMHO Sinn.

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

Partielle Klassen sind äußerst nützlich, um Anwendungsfälle zu spezialisieren. Es ist keine Verletzung eines OOP-Musters, sondern eine Möglichkeit, Codedokumente anzuordnen, die Folgendes bieten:

  1. Möglichkeit, die Klassen-/Typdefinition in mehrere Dateien aufzuteilen. Für große Codedateien ist dies die Funktion Wartbarkeit++.
  2. Möglichkeit für Compiler/Build-System, bedingte Verknüpfung zur Kompilierzeit zu verwenden. Analogie MSBuild, konkreter Anwendungsfall in C#: DBML, Designerklassen und noch mehr ausgefallene Sachen wie https://github.com/dotnet/corefx/pull/2045/files.
  3. Inhärenter Schutz, damit sich zwei (oder mehr) Entwickler beim Einchecken des Codes nicht begegnen. Konfliktlösung schlägt! :)
  4. Sie können Code in der Hauptpartialklasse generieren und dann eine weitere Partialklasse für benutzerdefinierte Überladungen erstellen. Funktioniert perfekt!

Ich glaube an die Trennung von Geschäftslogik und Datenschichten in separate Klassen und verwende hauptsächlich statische Methoden in diesen Schichten. Ich sehe wirklich nicht, wie es mehr Code und weniger wartbar sein könnte.

Während die Erweiterungsmethode ein Kernmerkmal der Sprache ist, das von OO-Mustern beeinflusst wird und zur Kompilierzeit verarbeitet wird, beschäftigen sich Teilklassen mit dem Dokument-/Code-Layout, das in der Vorkompilierungsphase zusammengefügt werden muss. Trotz der Ähnlichkeiten in partiellen Klassen, abstrakten Klassen und Erweiterungsmethoden gibt es eine klare Unterscheidung.

:+1: um die harmlosen "Partial Classes" nach TypeScript zu bringen.

Mein Anwendungsfall für partielle Klassen ist die Codegenerierung – mein Team muss in der Lage sein, einen Teil der Klasse in einer Datei automatisch zu generieren und benutzerdefinierte Methoden und Eigenschaften manuell in einer anderen Datei hinzuzufügen. Ich bin etwas verwirrt, warum @RyanCavanaugh "nicht sicher ist, ob diese Situationen in JavaScript/TypeScript zutreffen", da dieser Anwendungsfall nichts mit der gewählten Sprache zu tun hat.

Weder Dekoratoren noch Erweiterungsmethoden lösen das Problem der Codegenerierung so elegant wie partielle Klassen, und jede hat erhebliche zusätzliche Komplexitäten.

+1

+1

+1 für Codegenerierungszwecke.

In der C#-Umgebung würde die Integration eines Transpilers von C#-Klassen in TypeScript-Klassen die Notwendigkeit beseitigen, zwei verschiedene Definitionen von Klassen zwischen der Server- und der Clientseite zu halten, da die Clientseite, auch bekannt als TypeScript-Klasse, automatisch generiert würde und die Teilklasse dass dieses Problem erfordert, würde eine Anpassung bei Bedarf ermöglichen, während weiterhin in nativem TypeScript entwickelt wird.

+1 für Codegenerierungsszenarien

+1 extrem hilfreich für die Codegenerierung

Warum nicht die Vererbung für die Codegenerierung verwenden?

Die Vererbung ist unordentlich und hat mehr Overhead.

Am Mo, 10.08.2015, 10:09 Uhr schrieb Gorgi Kosev [email protected] :

Warum nicht die Vererbung für die Codegenerierung verwenden?


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/Microsoft/TypeScript/issues/563#issuecomment -129468291
.

​Vererbung erzeugt nutzlose Namenskopplungen

Vererbung ist weniger toll, weil sie:

  1. Vertieft die Prototypenkette unnötig und verlangsamt die Instanziierung,
    obwohl das für die meisten Apps keine große Sache ist, wahrscheinlich alles außer Spiele;
  2. Aus Mangel an Abstract und Override verliert entweder etwas Typsicherheit oder
    führt die Notwendigkeit für einige rücksichtslose Muster ein, wie das Casting zwischen den beiden
    Typen;
  3. Ist insgesamt verwirrend, da eine Basisklasse die Idee vermittelt, dass
    es kann durch andere Klassen erweitert werden, was bei Codegen selten der Fall ist

Nicht zu sagen, dass Typoskript partielle Klassen haben muss, um Codegen zu unterstützen, nur
dass Teilklassen darin so viel besser sind als Vererbung oder
Komposition.

@JoshMcCullough Der Vererbungsaufwand in JS ist minimal, und ich sehe nicht, wie es chaotischer ist als Teilklassen: Mit diesen können Sie eine Klasse möglicherweise in 10 Dateien aufteilen und Ihre Methoden überall verfolgen.

@yahiko00 Über was für eine "nutzlose Namenskopplung" reden wir hier? Beziehen Sie sich auf die Dinge, die Sie unten tun müssen, um Nr. 2 zu erhalten (den Namen der erweiterten Klasse fest codieren)?

@hdachev

  1. Es gibt etwas Overhead, aber es ist ziemlich minimal - nur bemerkbar, wenn Sie Dinge tun, die direkt in ein paar Maschinenanweisungen übersetzt werden
  2. Guter Punkt - Sie erhalten die erweiterte Klasse nicht, wenn Sie auf die generierte Klasse von anderen generierten Klassen verweisen müssen.
  3. Diese Klassen sind in der Tat dazu gedacht, erweitert zu werden - sonst könnten Sie sie generieren und damit fertig sein, oder?

AFAIK das ist nicht auf dem ES7+ Radar, oder? Das könnte problematisch sein...

Auf jeden Fall ist das Anhängen zusätzlicher Dinge an den Prototyp einer vorhandenen Klasse in JavaScript ziemlich trivial und überhaupt nicht ungewöhnlich, daher könnte es eine gute Idee sein, dafür eine Syntax zu haben...

In TS ist es einfach, aber der JS hinter den Kulissen würde die Menge verdoppeln
"Protoyping", wenn Sie Basisklassen für alle Ihre generierten Daten verwenden
Objekte. Wahrscheinlich keine ernsthaften Auswirkungen auf die Leistung, es sei denn, Sie haben eine Menge
Datenobjekte, aber es ist immer noch unnötig, wenn wir wissen, dass "partielle"
Klassen" möglich.

Am Mo, 10.08.2015 um 11:03 Uhr Gorgi Kosev [email protected]
schrieb:

@JoshMcCullough https://github.com/JoshMcCullough Vererbungs-Overhead
in JS ist minimal, und ich sehe nicht, wie es unordentlicher ist als Teilklassen:
Mit diesen können Sie eine Klasse möglicherweise in 10 Dateien aufteilen und Ihrem nachjagen
Methoden überall.

@yahiko00 https://github.com/yahiko00 Was für ein "nutzloser Name"
Kupplung" reden wir hier? Beziehst du dich auf die Dinge, die du brauchst
zu tun, um Nr. 2 unten zu erhalten (den Namen der erweiterten Klasse fest codieren)?

Klasse MyClass erweitert GeneratedMyClass { ... }

@hdachev https://github.com/hdachev

1.

Es gibt etwas Overhead, aber es ist ziemlich minimal
https://jsperf.com/prototype-chain-vs-direct-calls - nur auffällig
wenn Sie Dinge tun, die direkt auf ein paar Maschinen übersetzt werden
Anweisungen
2.

Guter Punkt - du bekommst die erweiterte Klasse nicht, wenn du musst
referenzieren Sie die generierte Klasse von anderen generierten Klassen.
3.

Diese Klassen sind in der Tat dazu gedacht, erweitert zu werden - sonst könnte man es tun
generieren und fertig damit, oder?

AFAIK das ist nicht auf dem ES7+ Radar, oder?

Auf jeden Fall zusätzliche Dinge an den Prototyp einer bestehenden Klasse anhängen
ist in JavaScript ziemlich trivial und überhaupt nicht ungewöhnlich, also könnte es a
gute Idee, dafür eine Syntax zu haben...


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an
https://github.com/Microsoft/TypeScript/issues/563#issuecomment -129483174
.

@ Davidhanson90 Diese Datei enthält keine Klassen. Wolltest du das in einem anderen Thread posten?

+1

+1

+100

+1

+1

+1 für Codegenerierung.
Ich habe mich mit anglejs und webapi beschäftigt und möchte ein Tool entwickeln, das im Wesentlichen automatische JS-Definitionen aus meinen c#-Objekten und -Diensten erstellt. Ich möchte diese Klassen dann erweitern können, ohne die "gerüsteten" JS-Definitionen bearbeiten zu müssen. Ich habe gesehen, dass einige andere Leute dies verlangen, und es scheint, als hätten wir ähnliche Anwendungsfälle.

+1 für Codegenerierung

+1 für die Codegenerierung, Angular hat viel Boilerplate-Code, wir machen bereits viele Generierungen davon, aber mit Teilklassen könnten wir viel mehr machen.

+1 noch einmal für die Codegenerierung. Der Versuch, Klassen in einer anderen Datei zu erweitern, ist bestenfalls chaotisch.

@RyanCavanaugh , was wird benötigt, um den "+1"-Modus zu verlassen und in eine produktive Richtung zu gehen?

-1 eine folgende Syntax ist besser für Mixins: #2919

Ich bin mir nicht sicher, warum wir nicht beide Teilklassen und die Mixins haben können; zwei völlig unabhängige Funktionen.

+1

Dies wäre schön, wenn Code generiert wird, aber Sie möchten ihn nicht ändern, um dem generierten Code Dinge hinzuzufügen.

+1

Ich habe einen Vorschlag, der diese beiden Anwendungsfälle erfüllen sollte:

  1. Sie möchten an verschiedenen Stellen Methoden Ihrer eigenen Klasse schreiben.
  2. Sie möchten der Klasse einer anderen Person neue Methoden hinzufügen, zB ein Builtin.

Für (2) würden Sie normalerweise nur den Operator :: , um die Infix-Syntax zu erhalten.

Wenn Sie jedoch möchten, dass eine alte Klasse Teil einer neuen Schnittstelle ist oder Sie dynamisch verteilen möchten, müssen Sie den Prototyp tatsächlich ändern.

interface ITimes {
    times(n: number): number
}

Array implements ITimes {
    times(n: number): number {
        return this.length * n
    }
}

// The compiler should check that all methods of ITimes and IOther are implemented.
Number implements ITimes, IOther {
    times(n: number): number {
        return this * n
    }

    other(): void {}
}

// The old types should typecheck with the new interface.
const x: ITimes = true ? [] : 0
x.times(3)

// The interface list can be empty. This essentially gives you partial classes.
MyClass implements {
    anotherMethod(): void {}
}

(Im Beispiel verwende ich String-Methodennamen, aber da es sich um eingebaute Typen handelt, wäre es besser, Symbole zu verwenden, sobald diese typgeprüft werden können.)

Eine Verbesserung gegenüber echten partiellen Klassen besteht darin, dass die Klasse eine einzige Definition hat und an anderen Stellen lediglich erweitert wird. Dies bedeutet, dass es einen klaren Ort gibt, aus dem die Klasse importiert werden kann, und die Übersetzung in JS erleichtert wird.

:+1: Ich würde auch gerne Teilklassen sehen.

Wie ist der Status dieser Funktion?

Dieser Anwendungsfall zum Beispiel:

Ich habe ein Math Paket, das eine Klasse definiert Set , mit Methoden Set#add , 'Set#remove'

// math.ts
export partial class Set {
  add(){}
  remove(){}
}

Ich habe ein optionales , schweres Relational Paket, das die Klassen Relation und Tuple .

Dieses Relational Paket würde auch eine Set#product Methode hinzufügen.

// relational.ts
///<reference path="./../math/tsd.d.ts"/>
partial class Set {
  product(){}
}

export class Relation(){}
export class Tuple(){}

Teilklassen würden es mir ermöglichen, Klassen flexibler zusammenzustellen. Wenn ich das schwere relational Paket nicht verwenden möchte, kann ich immer noch die grundlegende Set-Funktionalität verwenden. Andere partial Klassen kommen nur hinzu und fügen der Klasse zusätzliche Funktionen hinzu.

Ich kratze mir am Kopf, um etwas zu tun, das in diesem Fall eine schöne API ohne die Verwendung von Partials hat.

Alles, was ich mitbringen konnte, ist ein Repository-Muster.

// Without partials

// base

export class Base {
    static registerOperation(opName, method){
        this.prototype[opName] = method;
    }
    operation(name, ...args){
        return this[name].apply(this, args);
    }
}

// math.ts
import {Base} from './base';
class Set extends Base{
    // Define the methods here
    add(){}
    remove(){}
}

// Or here
Set.registerOperation("add", function(...){});
Set.registerOperation("remove", function(...){});

// relational.ts
import {Set} from './../math/math';

Set.registerOperation("product", function(...){});

// app.ts

import {Set} from 'math';

var set = new Set();
set.add // compiler error
set.remove // compiler error
set.product // compiler error

// have to use something like
set.operation("add", args);
// or
(<any>set).add(arg);

+1 Ich verwende t4, um Klassen und Proxys über WebApi zu generieren. Ich denke, die automatische Generierung wird in großem Umfang in Typoskript verwendet, und wenn es um die automatische Generierung geht, sind partielle Klassen erforderlich!

Es wäre großartig, um Aspekte derselben Klasse aufzuteilen, insbesondere in React
+1

+1 Code-Generierung und "Gerade genug Trennung" bei reinen wiederverwendbaren Datenobjekten mit kundenspezifischen Attributen für eine ähnliche Validierung, die sauber auf der Klasse definiert, aber in einem separaten Stück Quellcode gepflegt wäre.

+1 für Codegenerierung von Teilklassen und Handcode zusätzlicher Member für diese Klassen in separaten Dateien.

+1

+1 Ich habe eine große Methodenbasis in unserem js-API-Dienst, es wäre am besten, sie in Dateien aufzuteilen, wodurch jede Methode leicht zu verstehen ist.

api-Dienst wie fb (facebook) oder gq (google analytics) , bei dem Sie eine globale Klasse oder ein globales Objekt erhalten, das Sie während Ihrer gesamten Entwicklung verwenden können.

+1

Diese Funktion wäre auch für uns ein großes Plus.

Wir haben eine Middleware entwickelt, über die sich alle Arten von Clients mit unseren Servern verbinden und mit ihnen kommunizieren können.

Wir generieren einen Teil des Clientcodes basierend auf dem, was von den Servern bereitgestellt wird.

Bisher war alles in Ordnung. Aber jetzt möchten wir in der Lage sein, heterogene Sammlungen von Objekten (aber mit derselben Basisklasse) zu übertragen. Die übertragenen Objekte sind Teil des Codes, der basierend auf der Server-API generiert wird.

Um die Vererbungsmacht nutzen zu können, sind hier abstrakte Methoden der Schlüssel. Aber unsere Entwickler werden dem generierten Code keine Methoden hinzufügen, ich nehme an, jeder weiß warum ;)

Soweit ich verstanden habe (ich bin ein C#-Entwickler), würde uns die hier vorgeschlagene Lösung (https://github.com/Microsoft/TypeScript/issues/9) dies nicht erlauben.

Teilkurse wären also perfekt für uns. Wir würden die Klasse als partiell generieren, und wenn Entwickler Logik oder Methoden hinzufügen müssen, müssten sie einfach einen anderen Teil schreiben, wo immer sie wollen.

+1

+1 sehr hilfreich für die Codegenerierung

Ich frage mich, ob die Modulerweiterung dies als spezifisches Feature grundsätzlich negiert.

Wenn Sie eine generierte Klasse haben, sollten Sie in der Lage sein, etwas zu tun wie ...

import {MyClass} from "./MyClass.generated"

MyClass.prototype.partialMethod1 = function() {
  return true;
}
MyClass.prototype.partialMethod2 = function(abc: string) {
  this.doSomething(abc);
}

declare module './MyClass.generated' {
  interface MyClass {
    partialMethod1(): boolean;
    partialMethod2(abc: string): void;
  }
}

@disshishkov Das sieht nach einer guten Möglichkeit aus, es unter dem Deckmantel zu implementieren, aber ich hätte gerne eine erstklassige Unterstützung in der Sprache, ohne Prototypen manuell ändern und diese Schnittstelle warten zu müssen.

Ich stimme Elephant-Vessel zu. Der manuell erstellte Teil der Teilklasse sollte möglichst lose (zur Entwurfszeit in TS) von dem generierten Teil gekoppelt werden.

Der Vorschlag von @david-driscoll funktioniert in vielen Fällen. Soweit ich das beurteilen kann, haben Prototypen jedoch keinen Zugriff auf interne Variablen. Dies schränkt die Nützlichkeit dieses Ansatzes in Codegenerierungskontexten ein, in denen Sie die Kernteile Ihrer Klassen generieren und diese dann mit benutzerdefiniertem Code erweitern möchten.

+1

@david-driscoll, das sieht nach einer hervorragenden Möglichkeit aus, diese Funktion zu entzuckern. (würde die Möglichkeit hinzufügen müssen, auf private/geschützte Eigenschaften zuzugreifen). Ich frage mich, was mit mehreren partiellen Klassendeklarationen passieren würde? Wie wäre die gegenseitige Sichtbarkeit dieser?

++ 1 Das Fehlen von Teilbereichen tut mir wirklich weh, wenn ich versuche, meine automatisch generierten Modelle zu erweitern.

Ich denke, das einzige, was hier im Geltungsbereich ist, ist im Grunde das, was @david-driscoll vorgeschlagen hat - Sie könnten neue Methoden (die auf den Prototyp übertragen würden) und neue _nicht initialisierte_ Eigenschaften (die kein Codegen haben) deklarieren, aber keine neuen initialisierten Eigenschaften (weil diese Nebenwirkungen auf den Konstruktor-Codegen haben).

downvoted, pardon my french, partielle Klassen sind ein dummer Versuch, Ihre Gottklassen, die in OOP unvermeidlich sind, in mehrere Dateien aufzuteilen, damit sie einfacher zu verwalten sind (obwohl es immer noch Gottklassen sind)

mit OOP gibt es keine Zukunft für euch Leute (war schon da, weiß wovon ich rede)

komm zu FP, wir haben Cookies und eine Möglichkeit, ein Programm ohne eine einzige Klasse zu schreiben und das ist nicht so

Also erlauben wir dies im Grunde ohnehin schon durch interface A { method(): void } A.prototype.method = function() { }; ; dies in einen Zucker zu kodieren, macht genau das Sinn.

Eine Sache zum Fahrradschuppen ist das Schlüsselwort partial . Eine kurze historische Vignette: In C# sollte partial class ursprünglich extension class (was Sie bis auf eine auf alle Deklarationen setzen), aber es gab keine klare Unterscheidung, welche Deklarationen dies sein würden extension und welche Deklaration die Nicht-Erweiterungsdeklaration wäre. Stattdessen haben Sie den Modifikator partial , den Sie auf _all_ Klassen platzieren müssen.

Dies ist bei TypeScript _nicht_ der Fall; eher das Gegenteil. Hier darf nur eine Klasse (nennen wir sie die "_primary_-Deklaration") haben Konstruktoren / initialisierte Member-Felder; die primäre Deklaration erhält keinen neuen Modifikator. Jede andere Deklaration (nennen wir sie "_extension_-Deklaration") darf nur Statik, Methoden und nicht initialisierte Felder enthalten, und Sie _brauchen_ einen Modifizierer für sie, um anzuzeigen, dass sie nicht primär sind.

Die derzeit beste Vermutung ist

class Foo {
  x = 6; // only legal to initialize here
  constructor() { } // only legal to have constructor here
  someMethod() { }
}

// vvvvvvvvv thoughts?
   extension class Foo {
     someOtherMethod() {
     }
   }

:funkelt: :Fahrrad: :Haus: :funkelt:

Bikeshedding oder nicht, dies klingt schrecklich nach #311, das wegen wahrscheinlicher Beeinträchtigung zukünftiger ECMAScript-Standards abgeschafft wurde. Warum ist dies eine Überlegung wert, die richtige Mixin-Unterstützung jedoch nicht?

Die Verwendung des Schlüsselworts extension kollidiert mit Erweiterungsmethoden ? Oder wird dies Erweiterungsmethoden vollständig negieren?

@kitsonk Ich denke, der Mixin-Vorschlag hat viel mehr offene Fragen. Der partielle Klassenvorschlag hier ist nur eine Kodifizierung von Dingen, die bereits in TypeScript erlaubt sind, nur mit etwas syntaktischem Zucker (diese Funktion könnte buchstäblich als syntaktische Neuzuordnung von Dingen verwendet werden, die wir bereits haben).

@Elephant-Vessel Ich glaube nicht, dass Erweiterungsmethoden auftreten, wenn Teilklassen auftreten. Klassen sind der einzige Ort, an dem Erweiterungsmethoden angesichts unserer Einschränkungen sinnvoll sind, und der vorgeschlagene ES7+-Bindungsoperator ist eine bessere Möglichkeit, in erweiterungsähnlicher Syntax zu stecken.

@RyanCavanaugh : Für mich scheint es etwas einschränkend zu sein, dass eine Klasse primär ist und die anderen nicht. Wenn Sie Ihren Code so partitionieren möchten, dass eine Datei alle Methoden einer Klasse und die andere alle Eigenschaften enthält, scheint keine der beiden offensichtlicher primär zu sein, und warum sollten Sie gezwungen sein, sich zu entscheiden? Ist es nicht sauberer, Partials zu haben, bei denen sie alle gleich wichtig sind und vom Compiler zusammengeführt werden?

@RyanCavanaugh ... Ich würde es genau so machen wie c# ... es funktioniert großartig für die Codegenerierung ... was meiner Meinung nach das Hauptproblem war, das die Funktion in c# lösen sollte ... obwohl mein Gedächtnis unscharf ist ... hatte nie Probleme, gibt es schon seit Jahren und ist kampferprobt...

Wenn partielle/erweiterte Klassen keine initialisierten Felder haben können, wäre es meiner Meinung nach besonders nett, so etwas wie partielle Methoden zu unterstützen, die wir aus C# kennen , im Grunde ein leichtgewichtiger Vertrag speziell für partielle Klassen. So wie:

public partial class MyGeneratedClass
 {
     partial void Initialize();
     public constructor()
     {
          //...
         this.Initialize();
    }
 }

 public partial class MyGeneratedClass
 {
     partial void Initialize()  { //... }
 }

Die Notwendigkeit, Klassen von Drittanbietern partiellisieren/erweitern zu können, könnte ganz einfach(?) dadurch gelöst werden, dass partial/extends Allgemeinen optional, aber für die Verwendung partieller Methoden erforderlich ist.

Ich denke, dass dies dem Konzept, das wir hier wollen, eine ordentliche Ausdrucks- und Handlungskraft verleihen könnte.

Diejenigen, die nach Mixins suchen.

Betrachten Sie das Objekt initialisiert einen Vorschlag , mit dem (und der Flussanalyse) die Mixins elegant, natürlich, idiomatisch richtig gemacht werden können, was JavaScript angeht:

function enableBeingPositioned<a>(
   // hypothetical syntax
   something: a /* <-- before type */ => a & { x: number; y: number; } /* <-- after type */
): void { 
   something.x = 0;
   something.y = 0;
}
let value = {};
value.x; // <-- should not typecheck
enableBeingPositioned(value);
value.x; // <-- should typecheck

Sprachen wie Java bieten keine Teilklassen/Strukturen an. Es ist eine Nischenfunktion von C#. Die vollständige Nachahmung von C#-Konzepten für "partielle Klassen/Strukturen" ist hier der beste Weg.
Im Vorkompilierungsschritt könnte der TS-Compiler als erstes die Teilcodeblöcke im Speicher zusammenfügen und dann mit der regulären Kompilierungspipelineroute fortfahren. Dies wird mehr als genug sein, um sich für v1.0.0-preview1.0000 der Partial Classes-Funktion in TypeScript zu qualifizieren.
Alles, was über das hinausgeht, was C# bietet, kann in späteren Versionen eingeführt werden, wenn sich das Feature weiterentwickelt und seine Testversion/Vorschau überdauert. Die Eckfälle und ähnliches obskures Zeug können einzeln besprochen werden und wir können uns später um die Passform und das Finish kümmern ... IMO.

Ich stimme auch zu, sowohl Teil- als auch Erweiterungsklassen genau so zu machen, wie c#
ist es der beste Weg in Bezug auf Syntax und Semantik, beides funktioniert
sehr gut für ihre jeweiligen Anwendungsfälle. Teilklassen verbessern die
Benutzerfreundlichkeit des generierten Codes. Erweiterungsmethoden verbessern die Usability
von statischen Methoden, die auf Schnittstellen, spezifizierten Generika und dritten operieren
Parteitypen. Beide sind wirklich cool, aber bitte denk daran, dass sie nicht die sind
gleiche Funktion, ich sage dies hier wegen der oben vorgeschlagenen Syntax.

Erweiterungsmethoden würden dies ermöglichen (sry wegen fehlender Formatierung,
telefonieren):

erweitern MyType[] {
etwasSpecificToMyType() { ... }
}

WeirdThirdPartyDatastructure erweitern{
Ich auch() { ... }
}

Dass unter anderem Bibliotheken wie Unterstrich verwendet werden können
ohne die Cruft, was im Grunde bedeutet, die syntaktischen Vorteile von zu ernten
Erweiterung eingebauter Typen, ohne sie tatsächlich zu verschmutzen.

So kurz - behandeln wir die beiden nicht als ein und dasselbe, sie sind beide sehr
cool aber nicht das gleiche. Ich persönlich hätte gerne beides in unserem
Sprache.

Übrigens, als Randnotiz kann ich mir vorstellen, dass viele Leute bei der Idee zusammenzucken
Code-Generierung und sind bereit, jedem zu erklären, dass es keinen Platz hat
in Javascript, weil es idiomatischere Wege gibt, dasselbe zu erreichen.
Es gibt zwei Möglichkeiten, wie die Codegenerierung in einigen Fällen eine große Hilfe ist
Projekte, wie das, an dem ich gerade arbeite.

  • In leistungskritischen Projekten, wie Spielen, bei denen Sie es einfach tun
    Alles, um Ihr CPU-Budget mit nützlicher Arbeit auszuschöpfen, Codegen hilft eine Menge
    Code zu generieren, der sowohl einfach nachvollziehbar als auch hochgradig optimierbar ist
    / monomorpher Code, der wirklich gut juckt. Zum Beispiel in einem
    Entity/Component Game Engine, generierter Code kann bei einer Menge Sachen helfen
    wie sehr schneller Boilerplate-Code zum Zusammenfügen von Komponenten, Event
    Versand usw.
  • In Big-Business-Apps hilft generierter Code, extreme Laufleistungen zu erzielen
    das Typsystem, zum Beispiel durch emittierende Methoden mit sehr spezifischen
    Signaturen für Datenbankabfragen usw., die die Kompilierzeit maximieren
    Checks, hilft ungemein beim Refactoring und vereinfacht auch das Debugging erheblich
    weil Sie damit sehr einfachen Orchestrierungscode schrittweise durchlaufen können.
  • Der große ist, wenn Sie einige Komponenten synchron halten
    mehrere Sprachumgebungen, z. B. etwas im Zusammenhang mit Messaging
    wie Protokollpuffer oder einfach nur Json-Nachrichtenschnittstellen usw.

Als weiterer Nebenknoten für alle, die sich fragen, was teilweise
Klassen haben mit Codegen zu tun, dem Wert, die generierten Teile zu behalten
einer Klasse in eine separate Datei kommt aus den Quellcodeverwaltungsanforderungen -
das generierte Zeug ist normalerweise ein sich schnell änderndes Build-Artefakt und Sie
möchte nicht, dass es in Ihrem Repo festgeschrieben wird.

Ich mag die Idee, dies entsprechend einem bekannten und bewährten Modell dieses Konzepts zu implementieren, genau wie es C# hat. 'Nachahmung' hat einige negative Konnotationen, aber es hat einen erheblichen Wert, wenn es intelligent gemacht wird. Auf der anderen Seite besteht der 'intelligente'-Teil darin, sich der verschiedenen Umstände und Einschränkungen bewusst zu sein, daher werde ich nicht protestieren, wenn Partials für TypeScript nicht genau wie Partials für C# aussehen.

@Elephant-Vessel, ich stimme zu, dass es keine dito-Kopie von C#-Partials sein muss. Mein Vorschlag ist, als ersten Schritt das Schlüsselwort 'Registrieren von partial ' und 'Teilen nähen' zu verwenden und es als experimentelle/Vorschau-Funktion auszuliefern (damit Verbraucher nicht anfangen, sich im Produktionscode richtig darauf zu verlassen aus der Feder). Entwickeln Sie die Funktion später basierend auf der Community-Antwort weiter, bis sie produktionsbereit und RTM-fähig ist. Wenn wir uns im Voraus über alle möglichen kniffligen Fallstricke und Szenarien Gedanken machen, wird die Angelegenheit höchstwahrscheinlich weiter verzögert.

+1 - Zum Erweitern und Verwalten generierter Objekte.

+1 für die Pflege des generierten Codes

Ich habe Polyfill erstellt und meine große Klasse aufgeteilt.

Definieren Sie eine Klasse als Schnittstelle.

export class C {
  constructor() {
  }
}
export interface C {
  m(): void;
}

Implementieren Sie Klassenmember.

export default class extends C {
  m(): void {
  }
}

Implementierungen zusammenführen.

import {C} from './core';
import m from './member/m';

compose(C, m);
export {C}
import {assign} from './assign';
import {concat} from './concat';

export function compose<T extends new (...args: any[]) => any>(target: T, ...sources: T[]): T {
  return concat([target], sources)
    .reduce((b, d) => {
      void assign(b.prototype, d.prototype);
      for (const p in d) if (d.hasOwnProperty(p)) b[p] = d[p];
      return b;
    });
}

https://github.com/falsandtru/spica/commit/a6ff30da5319db5f25f703a29da48fc0f7dbe2fe

Ich halte dies aus einem bestimmten Grund für eine schreckliche Idee: Sie wird die bereits komplizierten Regeln für globale, Ambient-, externe, Namespace- und spröde Deklarationsreihenfolge-abhängige Vererbungsprobleme erheblich verschlimmern. Dies ist nicht C# und Namensauflösung und Memberdeklarationen sind sehr unterschiedlich.

Verwenden Sie vielleicht ein Objekt oder einen Namensraum anstelle einer Klasse, wie das aufschlussreiche Modulmuster, wenn Sie dies wirklich tun müssen. Sonst ist deine Klasse wahrscheinlich einfach zu groß.

Außerdem können Dekoratoren verwendet werden, um Verknüpfungen zwischen generiertem Code und handgeschriebenem Code zu implementieren.

Hast du andere Lösungen?

Ich würde das gerne auch zu TS hinzufügen

+1 für Codegenerierungszwecke (DTOs aus einer WCF-Dienstreferenz mit zusätzlichen partiellen Klassendefinitionen)

+1 für Codegenerierungszwecke. Mein Anwendungsfall ist: Ich habe React-Komponenten, deren render() Funktionen extern über React -Templates generiert werden.

Mit partial Klassen könnte ich solche Funktionen gegen die Hauptklasse (die Component ) überprüfen. Ohne Teilklassen kann ich nur die Funktion an die Hauptklasse binden und das Beste hoffen.

Mit dem nächsten TS 2.0 dachte ich, dass einige Fälle der Codegenerierung mit der this abgedeckt werden könnten.

Zum Beispiel in dem zuvor beschriebenen Fall anstelle von

partial class MyComponent extends React.Component<any,any> {
    render() {
        ...
    }
}

ich kann schreiben

function render<this extends MyComponent>()
        ...
}
MyComponent.prototype.render = render;

+1 Als Entwickler möchte ich Teilklassen, damit mehrere Vorlagen dieselbe Klasse über mehrere Dateien verteilt generieren/ändern können.

Meine Kommentare bezogen sich speziell auf Teilklassen, nicht auf Mixins. Die beiden sind grundsätzlich verschieden. Bei Partial Classes geht es darum, physischen Code aufzubrechen, Mixins darum, logisches Verhalten in wiederverwendbare Merkmale aufzuteilen, die andere Objekte sowohl auf Typ- als auch auf Wertebene bereichern.
Ich glaube nicht, dass partielle Klassen eine gute Idee für TypeScript sind. Mixins hingegen sind eine gute Idee, die eine erhöhte Ausdruckskraft bieten und sich hervorragend sowohl mit dem Typsystem von TypeScript als auch mit JavaScript-Idiomen verbinden, wie von @aleksey-bykov . betont

@wendellm können Sie sich einen sauberen Weg

+1 Ich brauche Teilunterricht!

können wir die Schnittstelle erweitern? Schnittstelle kann auch einige implementierte Funktionen haben, genau wie Swift:

interface Rect {
    x: number
    y: number
}

extension Rect {
    area() => this.x * this.y
}

Schnellversion:

protocol Rect {
    var x: Float {get}
    var y: Float {get}
}
extension Rect {
    func area() -> Float {
        return self.x * self.y
    }
}

+1

Codegenerierung und partielle Klassen gehen Hand in Hand.

Vererbung ist eine schlechte Lösung für eine im Wesentlichen verherrlichte #include Direktive.

Nehmen wir zum Beispiel Angular 2. Es werden keine Metadaten aus der übergeordneten Klasse

@tsvetomir das ist ein Angular-Problem, kein TypeScript-Problem.

Vererbung ist eine schlechte Lösung für eine im Wesentlichen verherrlichte #include-Direktive

Ja, Vererbung ist eine schlechte Lösung, aber das Problem besteht in erster Linie darin, Klassen zu verwenden. Sie haben ihren Platz, aber dieser ist sehr begrenzt. JavaScript-Klassen sind im Vergleich zu Klassen in anderen Sprachen ziemlich schwach und ausdruckslos.

Typoskript ist keine "Angular"-Sprache ... Nie war

Am 23. Juli 2016 um 21:46 Uhr schrieb Aluan Haddad < [email protected] [email protected] >:

@tsvet omirhttps://github.com/tsvetomir das ist ein Angular-Problem, kein TypeScript-Problem.

Vererbung ist eine schlechte Lösung für eine im Wesentlichen verherrlichte #include-Direktive

Ja, Vererbung ist eine schlechte Lösung, aber das Problem besteht in erster Linie darin, Klassen zu verwenden. Sie haben ihren Platz, aber dieser ist sehr begrenzt. JavaScript-Klassen sind im Vergleich zu Klassen in anderen Sprachen ziemlich schwach und ausdruckslos.

Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail, zeigen Sie sie auf Gi tHub anhttps://github.com/Microsoft/TypeScript/issues/563#issuecomment -234753589, oder schalten Sie das XJv7tc9LB0tPsIks5qYtH4gaJpZM4CcixK.

Ich sehe das Problem in keiner Weise als Angular-spezifisch. Es ist ein besonderer Fall, in dem Teilklassen geholfen haben können.

Die Anfrage stammt aus früheren Erfahrungen mit C# und dem Fehlen bekannter Funktionen. Der Vergleich ist unumgänglich, da TypeScript keine Anstrengungen unternimmt , sich von .NET zu distanzieren. Eine Form von Feature-Parität wird von seinen Benutzern erwartet.

Die Anfrage stammt aus früheren Erfahrungen mit C# und dem Fehlen bekannter Funktionen. Der Vergleich ist unumgänglich, da TypeScript keine Anstrengungen unternimmt, sich von .NET zu distanzieren. Eine Form von Feature-Parität wird von seinen Benutzern erwartet.

@tsvetomir als langjähriger .NET-Entwickler und leidenschaftlicher C#-Programmierer stimme ich grundsätzlich nicht zu.

Der von Ihnen zitierte Artikel ist nicht maßgebend und spiegelt kein offizielles Material des TypeScript-Teams wider.

Darüber hinaus widerspricht es direkt der TypeScript-Designphilosophie, wie sie von @ahejlsberg in zahlreichen Vorträgen, Interviews und Posts dargelegt wurde.

Darüber hinaus spiegelt der Standpunkt des zitierten Artikels ein grundlegendes Missverständnis über die Natur von TypeScript wider.
Ironischerweise sind die Gemeinsamkeiten von C# mit TypeScript tatsächlich dieselben wie mit JavaScript.
Diese Gemeinsamkeiten sind keine klassenbasierte Programmierung, sondern Konstrukte wie Closures und Funktionen höherer Ordnung.

C# oder nicht, wir brauchen partielle Klassen, die TypeScript helfen, näher an die Prototypfunktionen von Javascript zu kommen.

@yahiko00
TypeScript verfügt bereits über alle Prototypfunktionen von JavaScript.
Es ist eine Obermenge.

Es gibt mehrere Probleme mit dem Begriff partielle Klassen in TypeScript, einschließlich

  1. Im Gegensatz zu C# sind TypeScript-Klassendefinitionen (JavaScript) zwingend und nicht deklarativ. Sie erscheinen deklarativ, sind es aber nicht. Das bedeutet, dass sie von einer deterministischen Ausführungsreihenfolge abhängen.
  2. Das ECMAScript-Modulsystem basiert auf dem Import von physischen, nicht logischen Codeeinheiten.
    Sagen wir zum Beispiel, ich habe

_app/my-class-part-1.ts_

TypeScript export partial class MyClass { firstName = "John"; lastName = "Smith"; }

und
_app/my-class-part-2.ts_

TypeScript export partial class MyClass { fullName = this.firstName + ' ' + this.lastName; }

Wie kann ich diese Klasse importieren? Da ich aus keinem der Module importieren kann, stellen wir uns eine hypothetische Abstraktion in TypeScript vor, die es mir ermöglicht zu schreiben
_app/main.ts_

TypeScript import { MyClass } from './my-class';

Was würde das bedeuten? Auch wenn der TypeScript-Compiler daraus schließen könnte, dass _app/my-class-part-1.ts_ vor _app/my-class-part-2.ts_ geladen werden muss, kann er den Import der einzelnen Teile weder ungültig machen noch sicherstellen sie werden in der richtigen Reihenfolge von einem asynchronen Modullader wie RequireJS importiert oder was schließlich in Browsern implementiert wird.

Die ganze Vorstellung von partiellen Klassen steht im Grunde im Widerspruch zum ECMAScript-Modulsystem.

Update: Es müsste eine willkürlich komplexe Abhängigkeitsinferenz durchführen und ein sehr seltsames JavaScript ausgeben.

TypeScript verfügt bereits über alle Prototypfunktionen von JavaScript.
Es ist eine Obermenge.

Ich hätte mich besser ausdrücken sollen. Natürlich wissen wir alle, dass TypeScript eine Obermenge von JavaScript ist. Aber ich wollte sagen, dass partielle Klassen TypeScript-Klassen helfen würden, näher an JS-Prototypen zu kommen. Im Moment können wir nur "statische" und nicht erweiterbare Klassen haben, während wir mit einem Prototyp-Ansatz klassenähnliche Funktionen erweitern können.

Das Importieren von Teilklassen würde zu einer Erweiterung der aktuellen ES6-Syntax führen. Ich stimme zu. Wir könnten uns so etwas vorstellen:

import { MyClass } from ['app/my-class-part-1', 'app/my-class-part-2'];

TypeScript-Klassen basieren auf ECMAScript-Klassen und leiden daher unter deren mangelnder Aussagekraft. Ziehen Sie in Betracht, Funktionen, Module, "Namespaces" oder einfache Objekte zu verwenden, um das zu erreichen, was Sie benötigen.

Funktionen wollen wir mit dem Begriff der Klasse vermeiden.
Module oder Namespaces bringen einfache Erweiterbarkeit und haben nicht die gleiche Aussagekraft wie die Klassen von TypeScript. Außerdem kann ein Namespace oder ein Modul nicht instanziiert werden. Sie erfüllen nicht denselben Zweck wie Klassen.

@aluanhaddad Ich export partial class zuzulassen, während der Rest nur partial class Definitionen enthält. Sie importieren es von dem Ort, an dem es exportiert wurde. Aus deinem Beispiel:

_app/meine-klasse.ts_

export partial class MyClass {
    firstName = "John";
    lastName = "Smith";
}

_app/my-class.part.ts_

partial class MyClass {
    get fullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

_app/main.ts_

import { MyClass } from './my-class';

Was fehlt, ist eine Syntax, die dem Compiler mitteilt, wo die Teile zu finden sind. Dies ist kein Problem mit C#, bei dem Sie alle Dateien gleichzeitig verarbeiten. Dies kann eine spezielle Syntax sein, wie sie zum Zusammenführen von Deklarationen verwendet wird .

Es ist nicht erforderlich, dass partielle Klassen beliebige Definitionen zulassen. Sie können beispielsweise nur auf Methoden, Eigenschaften und Konstruktoren beschränkt werden. Dadurch wird die Ausführungsreihenfolge unbedeutend und der Compiler kann einen Fehler ausgeben, wenn ein Member dupliziert wird.

Ich verstehe nicht, warum die Modulerweiterung für diese Szenarien nicht gültig ist. Mit Rxjs5 hat es bei uns sehr gut funktioniert.

Sie erstellen einfach Ihre Basisklasse und generieren dann mit Ihrer Codegenerierung alle erweiterten Methoden, die Sie zusätzlich zur Basisklasse benötigen. Es spielt keine Rolle, ob der generierte Code schön ist, kein Mensch soll ihn schreiben.

Ist es ein perfekter Ersatz für Teilklassen? Ich vermute nicht, aber ich sehe keine partiellen Klassen, es sei denn, ECMAScript entscheidet, dass JavaScript sie benötigt. Allein die Semantik dafür, wie Teilklassen zwischen externen Modulen miteinander verbunden sind, tut mir im Kopf weh.

@david-driscoll Um es noch besser zu machen, können hinzugefügte Methoden ein this: Argument für eine stärkere Typprüfung deklarieren.

Im zitierten Beispiel der Modulerweiterung :

// observable.ts stays the same
// map.ts
import { Observable } from "./observable";
declare module "./observable" {
    interface Observable<T> {
        map<U>(f: (x: T) => U): Observable<U>;
    }
}
Observable.prototype.map = function (this: Observable, f) {
    // here "this" has the shape of the "Observable" class
}

Ja. Rxjs verwendet es noch nicht still, weil es ein 2.0-Feature ist und 2.0 noch nicht veröffentlicht wurde. Es steht später auf meiner Hitliste.

Ich verstehe, was du mit Modulen meinst. Eine mögliche Lösung wäre, nur einer der Dateien zu erlauben, eine Teilklasse zu exportieren, während der Rest nur Teilklassendefinitionen enthält. Sie importieren es von dem Ort, an dem es exportiert wurde. Aus deinem Beispiel:

_app/meine-klasse.ts_

export partial class MyClass {
    firstName = "John";
    lastName = "Smith";
}

app/my-class.part.ts

partial class MyClass {
    get fullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

Ich mag das syntaktische Konzept, aber das Problem ist, dass Sie gerade eine neue _Art_ von Quelldatei eingeführt haben, die als eine Art implizites Modul verwendet wird, wie ein Skript aussieht und auf eine bestimmte Weise geladen werden muss.

Was fehlt, ist eine Syntax, die dem Compiler mitteilt, wo die Teile zu finden sind. Dies ist kein Problem mit C#, bei dem Sie alle Dateien gleichzeitig verarbeiten. Dies kann eine spezielle Syntax sein, wie sie zum Zusammenführen von Deklarationen verwendet wird.

Das Zusammenführen von Deklarationen funktioniert für _declarations_, nicht für Quelldateien.

Es ist nicht erforderlich, dass partielle Klassen beliebige Definitionen zulassen. Sie können beispielsweise nur auf Methoden, Eigenschaften und Konstruktoren beschränkt werden. Dadurch wird die Ausführungsreihenfolge unbedeutend und der Compiler kann einen Fehler ausgeben, wenn ein Member dupliziert wird.

Alle diese _sind_ gewöhnlich reihenfolgeabhängig.

Bearbeiten: Das heißt, dass ihre Definition die Klasse ändert.

Wahrscheinlich hat dies schon jemand erwähnt, aber ein weiterer nützlicher Fall ist, wenn Sie einen Teil der Klasse von einem Codegenerator generieren und dann manuell etwas mehr Code direkt in Ihre Implementierung einfügen möchten.
Sie möchten nicht wirklich mischen oder abgeleitete Klassen verwenden.
Es ist immer noch eine Klasse - nur ein Teil wird automatisch generiert, ein anderer Teil manuell.

Übrigens: Wenn jemand TS-Typen aus C#-Klassen generieren muss, können Sie TypeScriptBuilder überprüfen

Danke, dass Sie dies bedenken!

Ich werde deinen TypeScriptBuilder ausprobieren ;)

Mein Vorschlag...

Was ist, wenn der Compiler nicht versucht, alle Teile zu finden? Was wäre, wenn ich andere Teile importieren müsste und alles kontrollieren müsste?

/MyClass.partial.ts

export partial class MyClass {
    firstName = "John";
    lastName = "Smith";
}

MyClass.ts

// v- this would NOT throw an error because the definition is marked as partial
import { MyClass } from "./MyClass.partial";

export class MyClass {
    get fullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

Dann...

  1. Wenn ich MyClass möchte, muss ich es aus MyClass.ts importieren
  2. Beim Kompilieren erzeugt MyClass.partial.ts ein Javascript, das MyClass.prototype wie hier zuvor gezeigt. Aber es exportiert eine Funktion, die den zu erweiternden Prototyp erhält.
  3. MyClass.partial.ts wird in MyClass importiert, nachdem MyClass definiert und seine Erweiterungsfunktion aufgerufen wurde.

Nebenbei bemerkt ... nichts hindert mich daran, den kompilierten Code direkt zu generieren. Aber ich verliere die ganze Größe von Typescript.

@svallory Ich denke, das ist hier definitiv der richtige Ansatz. Insbesondere weil Sie sagen, dass der generierte Code eine Funktion exportiert, die die Erweiterung verursachen würde, würde dies sogar bei asynchronen Importen funktionieren, da die Funktionen in der erforderlichen deterministischen Reihenfolge aufgerufen werden können.

Allgemeiner gesagt, und ich vergesse das Problem, wo darauf verwiesen wurde, wenn Zuweisungen an den Klassenprototyp die Form der Klasse beeinflussten, könnte dies viele Vorteile haben. Dies würde Mixin-Bibliotheken verbessern, Dekoratoren viel nützlicher machen und im Allgemeinen weniger vertikale Hierarchien fördern.

Es könnte für den Compiler schwierig sein, all dies zu verfolgen, aber es könnte wahrscheinlich funktionieren, indem man es explizit macht, wie Sie es vorschlagen.

Es wäre eine Erweiterung des Typsystems, wobei der Anwendungsfall der Teilklassen aus dieser Erweiterung herausfällt.

Ich habe es wie folgt gemacht:

Ich habe es wie folgt gemacht :
 Datei1 . ts
 Schnittstelle ifoo {
 a ( ) : nichtig ;
 }
 Klasse foo implementiert ifoo {
 a ( ) { /*etwas tun*/ }
 }
 Datei2 . ts
 /// <reference path="file1.ts" /> //nicht erforderlich
 Schnittstelle ifoo {
 b ( ) : nichtig ;
 }
 foo . Prototyp . b = ( ) = > { /*etwas tun*/ }
 Datei3 . ts
 /// <reference path="file1.ts" /> //nicht erforderlich
 Schnittstelle ifoo {
 c ( ) : nichtig ;
 }
 ( < ifoo > foo . Prototyp ) . c = ( ) = > { /*etwas tun*/ }
 Verbraucher . ts
 /// <reference path="file1.ts" />
 /// <reference path="file2.ts" />
 /// <reference path="file3.ts" />
 let f = new foo ( ) ;
 f . ein ( ) ;
 f . b ( ) ;
 f . c ( ) ;

Module Augmentation löst hier immer noch 90% des Problems. Angesichts der Beispiele von @svallory .

/MyClass.partial.ts

export partial class MyClass {
    firstName = "John";
    lastName = "Smith";
}

MyClass.ts

// v- this would NOT throw an error because the definition is marked as partial
import { MyClass } from "./MyClass.partial";

export class MyClass {
    get fullName(): string {
        return this.firstName + ' ' + this.lastName;
    }
}

Die Modulerweiterung wäre so etwas wie...

MyClass.ts

export class MyClass {
    firstName = 'John';
    lastName = 'Smith';
}

MyClass.generated.ts

import { MyClass } from './test';

Object.defineProperty(MyClass.prototype, "fullName", {
    get(this:MyClass) {
        return this.firstName + ' ' + this.lastName;
    }
});

declare module './test' {
    interface MyClass {
        readonly fullName: string;
    }
}

Es ist etwas ausführlicher als eine partielle Klasse, aber in Wirklichkeit wäre die partielle Klasse nur syntaktischer Zucker für diese Implementierung.

Die einzigen Fallstricke, die Sie heute nicht haben, wären:

  • Sie können nicht mit der this: MyClass Syntax auf private oder geschützte Felder zugreifen.

    • Dies kann in generiertem Code leicht gelöst werden, indem in any .

    • Vielleicht kann dies hinzugefügt werden, sodass Sie auf geschützte Mitglieder von this zugreifen können. Dafür mag es andere Regeln geben.

  • Der generierte Code sieht etwas einschüchternder aus, aber für den Verbraucher, wenn die Dinge einmal erweitert wurden, würden sie den Unterschied nie erkennen.

BEARBEITEN: Denken Sie daran, dies ist die TS 2.0+-Syntax.

@david-driscoll Ich stimme zu. Ich denke, das ist einfacher und ich mag es, dass es die zusätzliche Syntax nicht einführt. Wie Sie wissen, lehne ich partielle Klassen als spezifisches Sprachmerkmal ab, aber ich denke, es wäre von Vorteil, wenn TypeScript die Zuweisungen zu Prototypen im Allgemeinen nachverfolgt und die Form des Objekts entsprechend verfeinert. Ich denke, Ihr Ansatz ist der richtige Weg, um Klassen auf mehrere Dateien aufzuteilen.

@wongchichong Ihr Beispiel verwendet globale Klassennamen und /// <reference path="..."/> . Ich glaube nicht, dass das gut skalieren wird, obwohl Sie einen Namespace verwenden könnten, um die Situation zu verbessern.
Code, der als Module (dh externe Module) geschrieben wurde, ist ein ganz anderes Tier, da er einen Loader beinhaltet, der sich reihenfolgeabhängiger und impliziter Abhängigkeiten bewusst sein muss. Aus diesem Grund ist der Vorschlag von

Was ist, wenn jemand keine Module verwendet?

@pankleks Teilklassen sind immer noch eine schlechte Idee.

Zur Verdeutlichung meine ich, dass sie in einer Sprache wie JavaScript, wo Klassendeklarationen zwingend und nicht deklarativ sind, eine schlechte Idee sind. Selbst wenn Sie Namespaces verwenden, werden Sie Ihren Code am Ende in mehrere Dateien aufteilen, was bedeutet, dass Sie sich auf die Skript-Tag-Reihenfolge dieser Dateien verlassen müssen, damit dies überhaupt funktioniert.

In einer Sprache wie C# funktionieren partielle Klassen gut, aber das liegt daran, dass sie sich grundlegend von Klassen in JavaScript unterscheiden.

Es ist wichtig, sich daran zu erinnern, dass in JavaScript Klassendeklarationen nicht einmal hochgehoben werden, geschweige denn deklarativ.

Abgesehen von ES6 wird das "Klassen"-Konzept von TS definiert. JS hat _überhaupt_ keine Vorstellung von einer Klasse.
Es liegt also an TypeScript, zu entscheiden, was eine Klasse sein kann, nicht wahr?

Außer ES6,

Wir können ES6 nicht ausschließen, wenn wir über TS-Sprachfunktionen sprechen, da eines der TS-Ziele darin besteht , den aktuellen/zukünftigen ES-Spezifikationen zu folgen .

Stimmt das :/

Für große Systeme mit codegenerierten Klassen, dh Entities, Service Layer Clients etc., stellen Teilklassen nach dem C# Design eine sehr elegante Lösung dar, wenn generierter Code um zusätzliche Zustände und Verhalten erweitert werden muss. In meinem aktuellen Projekt, wo wir ~500 Code-Gen-Klassen haben, vermisse ich diese Funktion sehr.

Ich verstehe immer noch nicht, warum manche Leute so feindselig gegen eine Funktion sind, die sich anderswo als nützlich erwiesen hat, außer zu sagen, dass es eine schlechte Idee ist.

Es scheint, dass dies auf esdiscuss nicht viel diskutiert wurde, der einzige Thread, den ich gefunden habe, hat 9 Beiträge.

@yahiko00 Es ist nicht so, dass ich dem Konzept feindlich gegenüberstehe. Wie Sie sagen, ist es in Sprachen wie C# sehr nützlich.

Als begeisterter C#-Programmierer finde ich Teilklassen für bestimmte Aufgaben sehr hilfreich. Sie beeinträchtigen jedoch nicht die anderen Aspekte der Sprache. Sie unterbrechen keine schlüsselbezogenen Abstraktionen wie Namespaces, Assemblys und willkürlich geordnete Typdeklarationen.

JavaScript hingegen hat ein bestenfalls im Entstehen begriffenes Modulsystem. Klassen sind ein neues und meiner Meinung nach noch nicht sehr ausdrucksstarkes Merkmal der Sprache, sie brauchen Zeit, um zu wachsen.

Wenn wir für einen Moment einen Schritt zurücktreten und Erweiterungsmethoden in Betracht ziehen, eine weitere leistungsstarke und weitaus nützlichere Funktion von C#, würde ich sie gerne zu JavaScript hinzufügen, aber dabei gibt es grundlegende Probleme, die noch gelöst werden müssen.

Wenn wir einen Punkt erreichen, an dem partielle Klassen spezifiziert werden können, ohne weitaus grundlegendere Konzepte wie Module zu unterbrechen oder stark einzuschränken, werde ich dafür sein, sie hinzuzufügen.

Das heißt, wie @SaschaNaz betont , muss dies _muss_ in ECMAScript angesprochen werden.

Vielleicht kann jeder, der Interesse hat, einen neuen Thread auf http://esdiscuss.org eröffnen und die URL hier posten, damit wir dort weiter diskutieren können

PS: Oder auf mehr-GitHub-ähnlichem ES Discourse .
PS2: Oder auf auch-GitHub-ähnlichen-und-aktiveren WICG .

Ich würde auch gerne ein Konstrukt sehen, das die Codegenerierung für TS ermöglicht. Partielle Klassen eignen sich dafür hervorragend in C#.

Vielleicht übersehe ich etwas, aber es scheint mir, dass das Kernproblem darin besteht, eine Klasse mit Zugriff auf 'private' Variablen von irgendwo anders als im Konstruktor zu erweitern, vorzugsweise aus einer anderen Datei.

Basierend auf der Diskussion scheint ein Großteil der „sicheren“ TS-Innovation getan worden zu sein. Jetzt warten wir nur noch darauf, was das Leitungsorgan der ES tut, denn wir wollen in Zukunft nichts kaputt machen. Völlig gültig, aber ein wenig entmutigend, weil ich auf einen schneller fahrenden Zug mit TS gehofft hatte.

Voraussetzung ist , eine gute Entzuckerung zu finden :

Obwohl ich früher dachte, partielle Klassen seien ziemlich albern, weil Sie einfach direkt zur Klasse hinzufügen könnten, kann ich den Reiz sehen, da dies dazu führt, dass Ihre Methoden nicht aufzählbar sind und die Superbindung repariert wird (letztere ist derzeit unmöglich in .) ES6).

Wir müssen zuerst eine gute Entsiegelung für Klassen im Allgemeinen in kompositorische, zwingende Primitive finden, wie die alte toMethod. Aber sobald wir das haben, könnte es sinnvoll sein, etwas mehr Zucker wie Teilklassen hinzuzufügen, je nachdem, wie ergonomisch diese Primitiven am Ende sind – oder nicht.

Ich bin mir nicht sicher, was das genau bedeutet, aber wahrscheinlich so:

class A {
  foo() { return "foo" }
}
class B extends A {
}

partial(B, class {
  get foo() {
    return super.foo(); // should work
  }
});

(Kreuz auf esdiscuss gepostet)

Es scheint eine ziemlich einfache Möglichkeit zu geben, partielle Klassen in reinem JS zu implementieren (mit ES2017 getOwnPropertyDescriptors ). ES-Leute denken vielleicht, dass ein Syntaxzucker nicht einmal benötigt wird, um diesen winzigen Code zu entfernen.

function partial(base, extension) {
  extension.prototype.__proto__ = base.prototype.__proto__; // to enable 'super' reference
  const descriptors = Object.getOwnPropertyDescriptors(extension.prototype);
  delete descriptors.constructor; // must not override constructor
  Object.defineProperties(base.prototype, descriptors);
  
  return base;
}

Wenn Sie dies auf TS verwenden, ist natürlich ein Duplikat von interface erforderlich, um den vorhandenen Klassentyp zu erweitern.

@SaschaNaz Ich erwarte, dass Eigenschaften, die dem Konstruktor über getOwnPropertyDescriptors hinzugefügt wurden, für die IDE-"Autosuggestion" ausgeblendet werden (da sie zur Laufzeit hinzugefügt werden). Denken Sie daran, dass Typescript als JavaScript mit "Autosuggestion" geboren wurde (manchmal nennen es die Leute "stark getippt", aber was sie wirklich mögen, ist "Autosuggestion").

PS Warum Leute Teilklassen brauchen - Codegenerierung. Aber auch hier sollte die Codegenerierung sowohl von der IDE (einfaches "Tool" zur Anpassung an die Quelldatei, hierarchisches Ergebnis im Datei-Explorer, T4 oder ähnlicher "gemeinsamer Codegenerator"-Unterstützung) als auch von der Sprache (Teilklassen, Erweiterungsmethoden) unterstützt werden. Erst wenn man dies verstanden hat, wird es möglich zu verstehen, was Entwickler wirklich fragen. Wenn Sie kein vollständiges Bild sehen - "Teilklassen" sieht natürlich nach "Unsinn" aus.

@aluanhaddad : aber besteht die Hauptfunktion von TypeScript nicht darin, uns Sprachelemente bereitzustellen, die in JavaScript nicht vorhanden sind? Warum ist es keine gute Idee, eine Klasse in zwei partielle TypeScript-Dateien aufzuteilen, die dann zu einer einzigen JavaScript-Datei kompiliert werden?

Ich sehe wirklich kein Problem darin, der Community ein Tool zur Verfügung zu stellen. Und ich bin mir zu 100% sicher, dass es Entwickler geben wird, die es missbrauchen werden. Aber auch Entwickler, die genau wissen, wie man es benutzt. Aber haben wir nicht die gleiche Situation mit jedem Konstrukt irgendeiner Sprache?

+1 für Codegenerierungszwecke. Und ich stimme @rpokrovskij zu , warum wir TypeScript wählen, ich kann auch JavasScript direkt verwenden, nur weil es wie C# aussieht und ide-Unterstützung hat.

@greendimka Ich weiß nicht, wie dies funktionieren könnte, ohne von ES-Modulen

@xiexin36 TypeScript scheint mir mehr wie JavaScript als C# zu sein.
Es gibt Gemeinsamkeiten zwischen JavaScript und C#, aber ihre Vorstellungen von class liegen Welten auseinander.

@xiexin36 für die Codegenerierung können Sie immer noch die Modulerweiterung verwenden (wie ich bereits in diesem Thread bemerkt

@aluanhaddad Nun, es funktioniert ganz einfach:

@aluanhaddad Streng genommen: Javascript hat kein Konzept von Klassen (ES6-Klassen liefern nur einen syntaktischen Zucker). Wenn wir also versuchen, dem Konzept zu folgen, dass TypeScript so schwach ist wie JavaScript – sollten wir dann nicht Klassen von TypeScript wegwerfen? Sollten wir nicht einfach zu JavaScript zurückkehren?

@greendimka ES6-Klassen und TypeScript-Klassen sind ein und dasselbe.
TypeScript zielt nicht darauf ab, der Laufzeit von JavaScript zusätzliche Konstrukte hinzuzufügen.

ES6-Klassen sind _sehr_ glanzlos. Das bedeutet nicht, dass JavaScript keine mächtige Sprache ist (ist es). TypeScript bietet statische Typisierung, um Fehler zur Entwurfszeit zu erkennen, hochwertige Werkzeuge bereitzustellen, eine äußerst präzise und strenge Spezifikation von Komponentenschnittstellen zu ermöglichen und die Produktivität im Allgemeinen zu verbessern.

ES6-Klassen sind _sehr_ glanzlos, aber wenn TypeScript seinen eigenen Klassenbegriff einführt, würde dies direkt gegen seine Designziele verstoßen.

Vermeiden Sie einfach Klassen und Ihr Problem wird gelöst.

Nun, es funktioniert ganz einfach: Partielle Klassen ändern die Struktur des Codes in keiner Weise. Sie erlauben uns nur, Definitionen derselben Klasse in mehrere Dateien zu schreiben (die sowieso in ein einzelnes JS kompiliert werden).

Und fast jedes dem Menschen bekannte Werkzeug zerbrechen? Nein danke.

@david-driscoll Danke, ich werde es versuchen, aber ich benutze auch Angular 2.0, ich frage mich, ob ich damit Code generiere
@Input oder @Output , es wird funktionieren, ich werde es trotzdem versuchen.

@aluanhaddad es ist ein Schmerz zu sehen, wie Sie daran hängen, "Klassen? Javascript hat keine Klassen" zu wiederholen. Entfernen Sie Klassen aus Ihrem Kopf, lassen Sie nur JavaScript und hören Sie jetzt zu: Entwickler, die Codegenerierung verwenden, möchten eine Kompilierungseinheit in mehreren Dateien haben. Es gibt keine Klassen in dieser Sprache, nur Funktionen? OK, wir wollen Teilfunktionen. Und JavaScript ist dafür fast bereit: Funktionen dort können vor der Deklaration verwendet werden. Dort können wir natürlich andere Probleme treffen (zB um sicherzustellen, dass alle Teile/Dateien in die Ausführungsumgebung geladen werden), aber sie sind lösbar, und eigentlich wollen wir partielle Kompilierungseinheiten in TypeScript haben, nicht in JavaScrpipt. Typescript ist dafür zu 100 % bereit.

Übrigens, TypeScript-Team, geben Sie uns auch Teilfunktionen! Und bitte sagen Sie das gleiche dem C#-Team, da wir dort vorerst "Funktionen in Funktionen" haben. :)

Nur um sicherzugehen, dass Ihnen bewusst ist, dass Teilfunktionen eine sehr spezifische Bedeutung haben und das, was Sie beschreiben, keineswegs Teilfunktionen sind?
Die Codegenerierung ist nützlich, ich benutze sie auch.

@aluanhaddad . Verstehen Sie den Begriff "eine Zusammenstellungseinheit in mehreren Dateien" ? Javascript ist natürlich keine Kompilierungssprache, aber a) Funktion sollte vor der Ausführung vollständig geparst werden und wir können diese "Kompilierung" nennen. b) Typescript ist Kompilierungssprache.

Um Ihrer Fantasie zu helfen:

function partial func(arguments) {
  return function() {
    return codegenerated(arguments);
  };
}

function partial func(arguments) {
   function codegenerated(arguments){
      // ...
   }
}

Ich verwende auch nicht oft partielle Klassen: Um sie effektiv zu verwenden, müssen wir Codegenerierungsparameter im "manuellen" Teil speichern und um diese Konfiguration zu lesen, sollten wir einen guten Sprachparser (keine Reflektion) haben. Aber so ist es: Partielle Klassen sind nur ein Instrument von vielen, um die Codegenerierung komfortabel zu gestalten.

@rpokrovskij
Ich entschuldige mich, wenn ich antagonistisch rübergekommen bin. Ich meinte keine Beleidigung oder Respektlosigkeit.

Ihr Beispiel enthält Aspekte, die eine recht formale Beschreibung erfordern würden. Bei diesem Vorschlag ging es ursprünglich nicht darum, Codegenerierungsszenarien direkt zu ermöglichen.

@aluanhaddad....
"Vermeide einfach den Unterricht und dein Problem ist gelöst" - im Ernst, das ist eine Lösung für ein Problem?! Wahrscheinlich, wenn ich JavaScript vermeide, kann ich das Problem dieser ganzen Diskussion lösen. Auch eine Lösung, oder? Leider haben wir diese beschissene Sprache in unserem Universum, weil sie vor vielen Jahren das Glück hatte, ins Web zu kommen. Das ist jedenfalls ein Offtopic.

"fast jedes dem Menschen bekannte Werkzeug kaputt machen" - wie ist das möglich??? Wie?!?! Ich versuche mir vorzustellen, etwas zu zerstören, indem ich partielle Klassen in TypeScript verwende, aber ich kann nicht. Ich kann es einfach nicht. Bitte helfen Sie mir hier mit einem realen Beispiel.

Stellen Sie sich nun vor, Sie haben ein Auto gebaut, um Kisten zu transportieren. Es funktioniert ohne Probleme. Sie stellen einen Arbeiter ein, der das Auto belädt. Der Arbeiter nimmt zwei Kisten gleichzeitig und stellt sie in das Auto. Trotzdem funktioniert alles gut.
Eines Tages geht der Arbeiter zu einem anderen Unternehmen und Sie stellen ein neues ein. Der neue nimmt eine einzelne Kiste, lädt sie, nimmt eine weitere einzelne Kiste und lädt sie auch. Logisch: Alles in Ordnung. Aber du rennst herum und schreist: Halt, halt, wir haben einen Systemausfall! :)

"Vermeide einfach den Unterricht und dein Problem ist gelöst" - im Ernst, das ist eine Lösung für ein Problem?! Wahrscheinlich, wenn ich JavaScript vermeide, kann ich das Problem dieser ganzen Diskussion lösen. Auch eine Lösung, oder? Leider haben wir diese beschissene Sprache in unserem Universum, weil sie vor vielen Jahren das Glück hatte, ins Web zu kommen. Das ist jedenfalls ein Offtopic.

ES2015 hat mit Sicherheit viele Dinge falsch. ES5.1 hatte mit Sicherheit viele Dinge falsch gemacht. Fehlende Kurse gehörten meiner Meinung nach nicht dazu. Mein Punkt ist, dass Sie durch die Verwendung von Techniken wie dem aufschlussreichen Modulmuster die Notwendigkeit von Teilklassen vermeiden. TypeScript liefert Zucker für das aufschlussreiche Modulmuster Namespaces.

"fast jedes dem Menschen bekannte Werkzeug kaputt machen" - wie ist das möglich??? Wie?!?! Ich versuche mir vorzustellen, etwas zu zerstören, indem ich partielle Klassen in TypeScript verwende, aber ich kann nicht. Ich kann es einfach nicht. Bitte helfen Sie mir hier mit einem realen Beispiel.

Wenn Sie ES-Module verwenden, ist dies problematisch. Jedes Werkzeug, das darauf beruht, dass die physischen Artefakte des Compilers eine Entsprechung mit ihren nicht kompilierten Gegenstücken haben, würde diesem unterliegen. Das heißt, TypeScript könnte dies in der Ausgabe anpassen, eine massive Änderung, aber es würde dann JavaScript ausgeben, das nicht mit dem von Ihnen geschriebenen TypeScript übereinstimmt.

Im Grunde wird die Evolution einer Sprache von den Werkzeugen aufgehalten, die sich ohne die Evolution der Sprache niemals weiterentwickeln werden.
Sorry, aber ich sehe hier nur die Suche nach dem Grund sich nicht weiterzuentwickeln.

Welche Vorteile bringen Teilklassen mit sich, die man mit der Sprache nicht schon anders machen kann? Es ist ein schöner syntaktischer Zucker, sicher, aber was ist der wahre Gewinn? Gibt es ein konkretes Beispiel, außer es eher wie C# zu machen?


Nebenbei: Fürs Protokoll habe ich als C#-Entwickler angefangen, bin von dort zu JavaScript / C# gewechselt. Als TypeScript 0.8 angekündigt wurde, wurde ich verkauft, nicht weil es C# für JavaScript war, sondern weil es striktes JavaScript brauchte und es für Entwickler besser machte, die die starken Typen von C# mögen.

TypeScript ist nicht C# und sollte nicht unbedingt Features von C# erben, nur weil C# sie hat. Genauso wie C# keine Funktionen von TypeScript erben sollte. Ich kann nicht zählen, wie oft ich Funktionen wie Union-Typen in C# wollte, weil sie für TypeScript so großartig sind, aber noch nicht für die Sprache geeignet sind.


Bisher habe ich Code Generation und Code Organization gelesen.

Code - Generierung, Blick auf Modul Augmentation gibt es einige Mängel rief ich hier , aber ich bin sicher , dass sie fixiert werden.

Code-Organisation, ich denke, Regionen verwenden (lol)? Es gibt viele andere Möglichkeiten, Ihren Code zu organisieren. Wenn Sie eine God-Klasse haben (aus welchen Gründen auch immer), können Sie sie immer in viele God-Klassen aufteilen. An der Oberfläche ist die Götterklasse die Bedeutung, die jeder sieht und benutzt, unter dem Deckmantel jedoch besteht sie aus vielen Klassen, vielleicht als Eigenschaften der Götterklasse. Wenn Sie Teilklassen für die Organisation verwenden, würde ich argumentieren, dass Sie Ihren Code ein wenig umgestalten müssen, um zu versuchen, Ihren Code zu SOLID überprüfen.

Ich war in der Lage, die Erweiterung in die meisten Codegenerierungsszenarien einzupassen, die mir bisher begegnet sind.

Für Omnisharp-Client verwende ich hier die Interface-Erweiterung , wobei OmniSharp.Api.V2 eine per Reflection in C# generierte ist. Am Ende der Datei habe ich ein Tool, das alle Methoden für diese Schnittstelle ausblendet.

Für RxJS verwenden wir to, um alle unsere Methoden abzubilden , die sich auf Observable befinden .

Ich kann einige der Probleme mit Teilklassen einfach nicht lösen. Zum Beispiel, wenn wir 3 Teilklassen erhalten.

  • MyAwesomeClass1.ts
  • MyAwesomeClass2.ts
  • MyAwesomeClass3.ts

Geltungsbereich: Globales Modul (mit namespace / module )

Die globale Kompilierung scheint die einfachste zu sein. Da TypeScript bereits Namensräume zusammenführt.

Wenn mein tsconfig.json nur die Dateipfade für Class1 und Class2 enthält, wird alles, was sich in Class3 befindet, nicht automatisch zusammengeführt.

  • Dies scheint zunächst ein Benutzerfehler zu sein, aber es wird nicht sofort ersichtlich, warum die Methoden von Class3 nicht enthalten sind. Dies ist ein großes Usability-Problem, das zu Verwirrung führen wird.

Geltungsbereich: Externe Module (Import / Export)

Bei der externen Kompilierung wird jede Datei wirklich als Modul (oder Höllenassembly in der .NET-Welt) betrachtet, da jedes Modul eine explizite Liste aller seiner Abhängigkeiten (Importe) und aller seiner öffentlichen APIs (Exporte) hat.

Wie argumentieren Sie mit diesen Szenarien?

Wie verhält sich die Klasse bei nur einem Dateiverweis?
Führt es automatisch Class2 und Class3 zusammen?

  • Exportiert die Standarddefinition von Class1, Class2 und Class3 alle genau den gleichen Wert?
  • Welche Datei wird auf die Festplatte ausgegeben?
  • Wie sieht das zugrunde liegende JavaScript für alle unterstützten Formate aus (amd, umd, commonjs usw.)
// somefile.ts
import { MyAwesomeClass } from 'MyAwesomeClass1';

new mac = new MyAwesomeClass();
mac. // What methods are available here?

Müssen wir alle Instanzen der Klasse explizit importieren? (Wenn wir das tun, verfehlt das den Zweck imo).
Was passiert, wenn Sie alles in eine Datei importieren, aber nicht in eine andere, um die Methoden zu übertragen?
Dies könnte bei einem komplexen Abhängigkeitsgraphen, in dem die Klasse nur einmal verwendet wird, ohne die zusätzlichen Partials zu wirklich seltsamen Fehlern führen. Würden die Werte erhöht? oder würden die Methoden auf magische Weise nicht funktionieren, bis die andere Datei geladen ist, die sie einbringt?

// somefile.ts
import { MyAwesomeClass } from 'MyAwesomeClass1';
import { MyAwesomeClass } from 'MyAwesomeClass2'; // or maybe import 'MyAwesomeClass2';
import { MyAwesomeClass } from 'MyAwesomeClass3'; // or maybe import 'MyAwesomeClass3';

new mac = new MyAwesomeClass();
mac. // What methods are available here?

@david-driscoll Nur meine zwei Cent hier:

Es ist ein schöner syntaktischer Zucker, sicher, aber was ist der wahre Gewinn?

Ist nicht netter syntaktischer Zucker der springende Punkt jeder Sprache? Aus operativer Sicht brauchen wir nur Schleifen, if-Klauseln und Iterationen, um alles zu tun. Der Rest ist nur _schöner syntaktischer Zucker_, um produktiver zu sein und andere ähnliche nicht-funktionale Qualitäten bereitzustellen.

Und während Sprachen im Allgemeinen gut darin sind, einen Computer anzuweisen, sind sie im Allgemeinen gut im organisatorischen Teil des Schreibens von Code. Wir haben diese kulturellen Ad-hoc-Artefakte wie Objekte, Klassen, Vererbung und dergleichen, aber keine solide theoretische Grundlage, afaik, die den Bereich der Organisation von Operationen und all die Abstraktionen, die wir versuchen, in unserem Quellcode der Reihe nach zu konstruieren und darzustellen, wirklich erklärt gut damit arbeiten zu können.

Es gibt zwei Dinge, die ich an TypeScript liebe: 1. Es ermöglicht uns, typisiertes Javascript zu verwenden, so dass es plötzlich überschaubar ist, komplexe Systeme im Client zu erstellen. 2. Das Typsystem ist extrem ausdrucksstark (weil es gezwungen war, alle Arten von Mustern in Javascript auszudrücken, die die Leute ohne die Einschränkung eines Typsystems schreiben konnten).

Aber in Bezug auf die Strukturierung von Code denke ich nicht, dass es sehr viel weniger scheiße ist als jede andere Sprache. Und ich wünschte, wir könnten hier innovativer sein. Geben Sie Benutzern mehr Freiheit, mit dem organisatorischen Teil der Sprache zu experimentieren. Sich öffnen und streben nach neuer struktureller Ausdruckskraft, statt einschränkend und misstrauisch zu sein.

Partielle Klassen sind nicht nur speziell für die Codegenerierung sehr praktisch, sondern erhöhen die Freiheit bei der Organisation im Allgemeinen. Freiheit, die wir brauchen, um aus dieser Teergrube der Code-Organisation herauszukommen.

@david-driscoll was bringt es, Teiltöne zu haben? Nun, noch einmal: Codegenerierung.
Was ist an Ihrem Lösungsvorschlag falsch? Es ist ein Workaround. Noch eine weitere Problemumgehung (und ziemlich schmutzige Problemumgehung). Wir haben bereits eine beschissene Sprache (javascrtipt), die mit Workarounds gefüllt ist. Anstatt über ihre Hauptaufgaben nachzudenken, verbringen Javascript-Entwickler viel Zeit damit, über die Problemumgehungen nachzudenken. Mit Ihrer vorgeschlagenen Philosophie können wir die gesamte TypeScript-Sprache wegwerfen. Denn (Überraschung, Überraschung) kann das ganze Typensystem in reinem Javascript simuliert werden - mit Hilfe von Workarounds. Warum sich um eine ausdrucksstärkere Sprache (wie Typescript) kümmern, wenn Sie mit Workarounds alles simulieren können? Warum eine einzige Codezeile schreiben, wenn dasselbe in zwanzig Zeilen geschrieben werden kann? Bringen Sie die Gehälter zurück, die auf einer Reihe von geschriebenen Codezeilen basieren! Kurzer, ausdrucksstarker Code ist für Fotzen, nicht wahr?

Und nein: Die Anforderung, Partials in TypeScript zu haben, basiert nicht auf der Vorstellung, dass C# sie hat. Ich glaube nicht, dass TypeScript etwas haben sollte, nur um es zu haben, weil eine andere Sprache es hat.

Und schließlich: Warum denkst du, wenn du etwas nicht nutzt – niemand braucht es?

@greendimka Ich habe nicht versucht, Feindseligkeit zu entfachen: Schild:. Ich versuche einfach, die Szenarien zu verstehen oder wenn es solche gibt, die ich nicht kenne, die ehrlich gesagt durchaus möglich sind!

Denken Sie daran, ich gehöre nicht zum TypeScript-Team, ich bin nur ein Befürworter, aber das Team war hier ziemlich still. Das Team kann sich sehr wohl einmischen, wenn es etwas Bestimmtes zu sagen hat, und ich werde es ihnen nachstellen, wenn sie dies wünschen.

Einer der wichtigsten Mandanten, an den sich das TypeScript-Team gehalten hat, ist zu versuchen, TypeScript synchron mit der Richtung von ECMAScript zu halten und zu vermeiden, dass bestimmte Funktionen entwickelt werden, die dazu führen könnten, dass sie von der allgemeinen Richtung abweichen, in die sich JavaScript entwickelt.

Es ist nicht so, dass ich es nicht benutzen würde (ich würde es wahrscheinlich tun, wenn es existieren würde). Das Problem ist, wie es in dieser Ausgabe aussieht, haben teilweise Klassen Vorbehalte, so dass es zweifelhaft erscheint, dass es in Kürze implementiert wird. Dies wird wahrscheinlich noch eine Weile so bleiben, bis a) es ein Muss für einen hochrangigen Stakeholder wird oder b) ein Vorschlag in die späteren Phasen von TC39 eindringt.

Ich sehe Module Augmentation nicht als Workaround. Es ermöglicht Ihnen, das Typsystem zu erweitern, und ermöglicht viele der Codegenerierungsszenarien, die in diesem Thread beschrieben wurden. Dies ist ein Schritt in Richtung anderer Sprachfunktionen.

  • Ist es hässlich? Absolut hässlich wie die Hölle. Das heißt, wenn Sie den Code generieren, was ist der Unterschied? Nur Ihr Generierungstool muss sich Gedanken darüber machen, wie die Klasse erweitert werden kann. Sobald Sie Ihr Codegenerierungstool ausgeführt und Ihre Module eingebunden haben, erhalten Sie vollständige Intellisense- und Kompilierungsfehler usw.

  • Ist es perfekt? Weit davon entfernt! Ich sehe ein weitaus häufigeres Szenario, bei dem Mixins auf Sprachebene unterstützt werden müssen. Und ich denke, dass etwas mit Dekorateuren, wie es hier vorgeschlagen wird, sinnvoll ist, obwohl es auch hier keinen spezifischen Vorschlag gibt.

@david-driscoll, Entschuldigung, dass ich so extrem unhöflich war. Ich neige wirklich dazu, auf der Seite des positiven Fortschritts zu stehen.

Ich möchte dies, damit ich statische Implementierungen in eine Teilklasse einfügen kann.

Da es nicht so aussieht, als würde dies bald zum Tragen kommen, möchte ich einen Workaround vorschlagen, den wir gefunden haben. Es gibt einige Kommentare wie diese, aber ich habe keinen mit diesen Besonderheiten beim Lesen gesehen.

Wir möchten Partials für die Verwendung in einem Codegenerierungsszenario, in dem wir unseren generierten TypeScript-Code erweitern möchten. Wir generieren jedoch Modelle mit gegenseitigen Abhängigkeiten, sodass das Vererben von unseren Klassen im herkömmlichen Sinne nicht gut funktioniert. Bei den generierten Klassen, die auf andere Klassen verweisen, wird nicht der richtige Objekttyp referenziert, und wir würden am Ende ein komplexes Fabrikmuster erhalten, um die richtigen Instanztypen zu erstellen.

Am Ende haben wir unsere generierten Klassen in Basisklassen geändert, aber nur in der Klassendeklaration. Wir haben dann Stub-Klassen erstellt, die von unseren neuen Basisklassen geerbt wurden. Wir könnten diese neuen Klassen dann erweitern und sie würden ihren gesamten Inhalt von der Basisklasse erben.

Zum Beispiel:
Wenn wir eine Klasse Person generiert hätten, würden wir jetzt eine PersonBase generieren. Der gesamte generierte Code gehört in diese Klasse. Wir würden auch eine leere Klasse Person generieren, die PersonBase erweitert. Diese Klasse würde immer nur einmal generiert. Wir legen dann unseren gesamten generierten Code in PersonBase ab, und der gesamte benutzerdefinierte Code wird manuell in Person eingegeben. Alle generierten Verweise auf Person bleiben als Person und nicht als PersonBase. Auf diese Weise funktioniert IntelliSense weiterhin.

Datei 1: Basisklasse

module ViewModels {
    export class PersonBase {
        // Generated members
        public anotherPerson: Person;
        constructor(){
            // Generated constructor code
        }
    }
}

Datei 2: Tatsächliche Klasse

module ViewModels {
    export class Person extends PersonBase {
        // Custom methods
        public NewVariable: string = "NewVar";
        constructor() {
            super();
            // Custom constructor code
        }
    }
}

Dies hat unser partielles Klassenproblem mit generiertem Code gelöst. Ein großes Lob an Andrew Scott für die Idee.

Das würde mir auch sehr gefallen, da ich mit einem Codegenerator Code erzeuge und einige Änderungen daran vornehmen muss. Partielle Klassen ermöglichen es, den Code neu zu generieren, ohne die Änderungen später erneut hinzufügen zu müssen (was groß oder komplex sein kann).

Es gibt einen wichtigen Grund für die Verwendung von Teilklassen, der meiner Meinung nach noch nicht erwähnt wurde: die schrittweise Migration von JS zu TS. In Javascript, insbesondere vor ES6, können Klassen wie folgt aussehen:

Foo.prototype.someFunction = function() {/*....*/}

Und diese können ohne besondere Behandlung auf mehrere Dateien verteilt werden. Die Konvertierung einer solchen Codebasis in modernes TypeScript erfordert derzeit das Verschieben von Funktionen, damit sich alle Mitglieder einer Klasse in derselben Datei befinden, was eine ziemlich invasive Änderung sein kann. Bei Teilklassen konnte die Migration nur mit lokalen Bearbeitungen durchgeführt werden.

@RyanCavanaugh Sie erwähnen, dass alles, was hier verlangt wird, mit anderer TypeScript-Syntax syntaktisch verarbeitet werden kann:

Ich denke, der Mixin-Vorschlag hat viel mehr offene Fragen. Der partielle Klassenvorschlag hier ist nur eine Kodifizierung von Dingen, die bereits in TypeScript erlaubt sind, nur mit etwas syntaktischem Zucker (diese Funktion könnte buchstäblich als syntaktische Neuzuordnung von Dingen verwendet werden, die wir bereits haben).

Wie würde man das in TypeScript machen?:
Datei1.ts:

// Imagine this file is code generated and could be regenerated during development
export partial class Contact
{
    firstName: string;
    lastName: string;
    partial OnInit( args: any ) : void;
    constuctor( args: any )
    {
        this.OnInit( args );
    }
}
export class Address
{
    addr: string;
    city: string;
    state: string;
    zip: string;
}

Datei2.ts

// See where I'm going with this? This file would be hand edited and allows me to specify associations and children.
partial class Contact
{
    Addresses: string[] = [];
    partial OnInit( args: any ) void
    {
        this.firstName = args.firstName;
        this.lastName = args.lastName;
        this.Addresses.push( new Address() );
    }
}

Das Transpilieren des Obigen würde eine JS-Klasse für Contact ausgeben, etwa so:

var Contact = (function () {
    function Contact() {
         this.Addresses = [];
   }
   Contact.prototype.constuctor = function (args) {
       this.OnInit( args );
   };
   Contact.prototype.OnInit = function (args) {
       this.firstName = args.firstName;
       this.lastName = args.lastName;
       this.Addresses.push(new Address());
   };
   return Contact;
})();

var Address = (function () {
    function Address() {
    }
    return Address;
})();

Beachten Sie, dass ich am Ende eine Klasse namens Contact möchte und nicht zwei separate Klassen in eine dritte unterteilen muss.

@cosmoKenney

Hier ist ein Beispiel für etwas, das funktionieren wird. Es ist syntaktisch nicht so aufgebauscht wie partial aber es funktioniert und ist eine sehr funktionale Lösung.

// address.ts
export class Address
{
    addr: string;
    city: string;
    state: string;
    zip: string;
}
// contact.impl.ts
import { Address } from './address';

// Class implementation, do the things here that are not code generated
export class Contact {
    firstName: string;
    lastName: string;
    addresses: Address[];
    constructor(args: any) {
        this.onInit(args);
    }
}
// extending the interface here
// define methods you know will need in the constructor only
// This only applies to the constructor however
export interface Contact {
    onInit(args: any): void;
}
// contact.partial.ts
import { Contact } from './contact.impl';

// Implement the extended contract here
Contact.prototype.onInit = function(this: Contact, args: any) {
    this.addresses = args.addresses.concat();
    // do stuff;
};

// Adding another method (not part of the extended interface)
Contact.prototype.somethingAwesome = function(this: Contact) {
    // do awesome stuff here
};

// Tell TypeScript "I added this here!!!!"
declare module './contact.impl' {
    interface Contact {
        somethingAwesome();
    }
}
// contact.ts
import { Contact } from './contact.impl';
import './contact.partial';

// Bring it all together (perhaps there are more than one partial class?)
export { Contact };
// main.ts
import { Contact } from './contact';

// use the contact!
const contact = new Contact(['my', 'args']);
const {firstName, lastName} = contact;
contact.somethingAwesome();

Alternativ können Sie die Schnittstelle auch per Code generieren und die Schnittstellenerweiterung verwenden, um dies zu implementieren.

Es mag auch Möglichkeiten geben, die neue Mixin-Funktionalität zu verwenden, aber ich habe mich selbst noch nicht genug damit befasst, um eine qualifizierte Antwort zu geben.

@david-driscoll Wow. Mein Kopf ist gerade explodiert.

Ich frage mich, ob die Community am Ende mit einer Abzweigung enden wird, die einfach Teilklassen unterstützt, ohne ein Problem daraus zu sprengen.
Habe bisher keine wirklichen Argumente gegen Teilklassen gehört. Nur wenige Gründe, eine Faulheit zu rechtfertigen.

@greendimka

Ich frage mich, ob die Community am Ende mit einer Abzweigung enden wird, die einfach Teilklassen unterstützt, ohne ein Problem daraus zu sprengen.
Habe bisher keine wirklichen Argumente gegen Teilklassen gehört. Nur wenige Gründe, eine Faulheit zu rechtfertigen.

Ich bin mir nicht sicher, was Sie hier sagen wollen. Aber wenn das allgemeine Gefühl in der Community ist, dass wir die gleichen Ergebnisse mit vorhandenen Sprachfunktionen erzielen können, dann brauche ich nur einige Beispiele dafür. Was @david-driscoll oben gepostet hat, übersteigt mein Verständnis weit. Und scheint das Problem nicht ganz zu lösen. Soweit ich das beurteilen kann, hat er meine Absichten sogar falsch interpretiert.
Mein Hauptanliegen ist es, die skalaren Eigenschaften der Klasse durch Code zu generieren, wie z. B. eine Pojo- oder Modellklasse. Aber ich muss in der Lage sein, in einer separaten Datei oder sogar in derselben Datei, aber nicht innerhalb der Primärklassendefinition, die Assoziationseigenschaften hinzuzufügen (damit ich eine neu codegenerierte Primärdefinition über das Original einfügen kann).
Zum Beispiel würde meine Contact-Klasse von oben Code mit firstName und lastName generieren. In meiner separaten Definition würde ich jedoch die Definition und Initialisierung der Sammlung von Adressobjekten hinzufügen.
Mein Codegenerator kennt nur die Attribute der Klasse, nicht die Assoziationen, daher kann er die Adresssammlung nicht codieren - wie in Davids Beispiel.

@cosmoKenney es war nicht ganz klar, wo die Adresse stehen soll. Verzeihen Sie, dass ich den Kontext falsch verstehe. Ich versuche nur zu helfen, die Alternativen aufzuzeigen. Es gibt viele Funktionen, die ein ähnliches Verhalten ermöglichen, ohne etwas in den Compiler zu stecken, wie z. B. Teilklassen, die viele zusätzliche Überlegungen und potenzielle Probleme bei der Implementierung beider Modulsysteme (intern / extern) haben.

In Ihrem Fall würde das Generieren einer abstrakten Basisklasse oder einer Schnittstellengenerierung funktionieren, dann erbt Ihre andere Klasse davon. Dann wird die Tatsache, dass Ihre Klasse generiert wurde, immer noch ausgeblendet.

dh:

// address.partial.ts
export interface IAddress
{
    addr: string;
    city: string;
    state: string;
    zip: string;
}

// address.ts
import { IAddress } from './address.partial';

export class Address
{
    constructor(args: any) {

    }
}
export interface Address extends IAddress{}

// contact.partial.ts
import { IAddress } from './address.partial';

export interface IContact {
    firstName: string;
    lastName: string;
    addresses: IAddress[];
}

// contact.ts
import { Address } from './address';
import { IContact } from './contact.partial';

// Class implementation, do the things here that are not code generated
export class Contact {
    addresses: Address[] = [];

    constructor(args: any) {
        this.firstName = args.firstName;
        this.lastName = args.lastName;
        this.addresses.push( new Address("address?") );
    }

    public somethingAwesome() {
        //
    }
}
export interface Contact extends IContact {}

// main.ts
import { Contact } from './contact';

const contact = new Contact(['my', 'args']);
const {firstName, lastName} = contact;
contact.somethingAwesome();

@cosmoKenney : @david-driscoll bietet eine interessante Lösung, aber es fehlt noch die Einfachheit echter Teilklassen. Wie meine persönlichen Experimente gezeigt haben, verwenden Entwickler einfach keine "Partials", die auf diese Weise erstellt werden. Obwohl es sich um eine gute Lösung zur Problemumgehung handelt, ist die Leichtigkeit und der Komfort von Teiltönen nicht vorhanden.

Im Moment weiß ich nicht, wie der TypeScript-Compiler intern arbeitet. Ich kann nur davon ausgehen, dass es alle Quelldateien liest, weiterarbeitet und JS-Dateien ausgibt. Wenn es so ist, sehe ich keine Probleme beim Lesen einer einzelnen Klasse aus mehreren Quelldateien. Wenn zwei oder mehr Quelldateien einer einzelnen Klasse widersprüchlichen Code bereitstellen (z. B. dieselbe Eigenschaft zweimal definiert), löst der Compiler einfach eine Ausnahme aus. Genauso wie wenn Sie syntaktisch ungültigen Code schreiben.

@greendimka , @david-driscoll
Ich habe versucht, Davids Beispiel von oben zu kompilieren, und ts mag es nicht:

C:\TestProjects\TypeScriptFakePartialClassTest>tsc -m amd address.partial.ts address.ts contact.partial.ts contact.ts main.ts
address.ts(4,14): error TS2300: Duplicate identifier 'Address'.
address.ts(10,18): error TS2300: Duplicate identifier 'Address'.
contact.ts(7,14): error TS2300: Duplicate identifier 'Contact'.
contact.ts(11,14): error TS2339: Property 'firstName' does not exist on type 'Contact'.
contact.ts(12,14): error TS2339: Property 'lastName' does not exist on type 'Contact'.
contact.ts(20,18): error TS2300: Duplicate identifier 'Contact'.
main.ts(5,8): error TS2459: Type 'Contact' has no property 'firstName' and no string index signature.
main.ts(5,19): error TS2459: Type 'Contact' has no property 'lastName' and no string index signature.

Außerdem stimme ich @greendimka zu, dass dies zu komplex ist, um es in einer großen Anwendung Hunderte Male zu verwenden.

@greendimka Ich weiß auch nicht, wie der Compiler funktioniert, aber unterschätze die Aufgabe nicht. JavaScript ist nicht .NET und Module sind nicht global verfügbar (Sie sollten sie buchstäblich importieren)

Ich würde dies gerne implementiert sehen, aber diese Aufgabe bringt einige Dinge mit sich, die sorgfältig durchdacht werden müssen, wie zum Beispiel:

  • Wenn Sie einen Teil der Klasse in einer Datei A definieren, einen Teil in einer Datei B, welcher sollte die vollständige Klasse nach dem Tranpilieren enthalten? Soll ein neues generiert werden?
  • Sollten alle Dateien, die Teilmaterial enthalten, dieselbe Klasse exportieren?
  • Wie vermeide ich zyklische Abhängigkeiten, wenn ich die Hauptdatei für diese zusätzlichen benötige?
  • Was passiert, wenn ich mehr Dinge auf dem Modul exportiere als nur die Klasse selbst?
  • Namenskonflikte prüfen?

und so weiter...

@greendimka Siehe meine Antworten unten: (BEARBEITEN: Dies war an @WoLfulus gerichtet , sorry @greendimka):

Wenn Sie einen Teil der Klasse in einer Datei A definieren, einen Teil in einer Datei B, welcher sollte die vollständige Klasse nach dem Tranpilieren enthalten? Soll ein neues generiert werden?

Ich würde mich sehr freuen, wenn Datei A.js die vollständige Definition hat und Datei B abgekürzt wird. Vielleicht mit einem vorgefertigten Kommentar. Die meisten von uns bündeln sowieso, so dass die unzähligen .js-Dateien, die gebündelt werden, am Ende im Wesentlichen zu einem nachträglichen Gedanken werden.

Sollten alle Dateien, die Teilmaterial enthalten, dieselbe Klasse exportieren?

Dies ist so ziemlich durch meine Antwort auf die erste Frage beantwortet.

Wie vermeide ich zyklische Abhängigkeiten, wenn ich die Hauptdatei für diese zusätzlichen benötige?

Ich weiß nicht. Ist es nicht die Aufgabe des Modulladers, dieses Szenario zu erkennen?

Was passiert, wenn ich mehr Dinge auf dem Modul exportiere als nur die Klasse selbst?

Ich sehe das Problem darin nicht. Mit anderen Worten, wenn B.ts sowohl eine partielle Definition als auch einige andere nicht-partielle Klassen hat, sollte B.js den oben erwähnten vorgefertigten Kommentar UND die Definitionen der nicht-partiellen Klassen enthalten. Einfach, denke ich.

Namenskonflikte prüfen?

Wie würden Sie mit einem Namenskonflikt enden? Wenn Sie die Klasse meinen, würde das Schlüsselwort "partial" das lösen. Aber wenn dann zwei andere Dateien beide Klassen mit dem gleichen Namen, aber ohne das Schlüsselwort "partial" definieren, sollte der Compiler einen Fehler über doppelte Typen ausgeben - wie es jetzt der Fall ist. Wenn Sie jedoch von zwei Teildefinitionen derselben Klasse sprechen, die eine Eigenschaft oder Methode mit demselben Namen definieren, sollte der Compiler einen Fehler über doppelte Member ausgeben - wie jetzt.

@WoLfulus , @cosmoKenney hat gut geantwortet. Um es mit Ihrer ersten Frage (zu A- und B-Dateien) besser zu machen: Als Sprachdesigner hat man das Privileg, Regeln zu definieren. Damit meine ich, dass Datei A einen solchen Code "Teilklasse X" und Datei B einen solchen Code "Teil(DateiX) Klasse X" haben kann, der fileX.js erzeugt.

@cosmoKenney

Wie vermeide ich zyklische Abhängigkeiten, wenn ich die Hauptdatei für diese zusätzlichen benötige?
Ich weiß nicht. Ist es nicht die Aufgabe des Modulladers, dieses Szenario zu erkennen?

TypeScript hat keinen Modullader.

@greendimka

Ich frage mich, ob die Community am Ende mit einer Abzweigung enden wird, die einfach Teilklassen unterstützt, ohne ein Problem daraus zu sprengen.
Habe bisher keine wirklichen Argumente gegen Teilklassen gehört. Nur wenige Gründe, eine Faulheit zu rechtfertigen.

Das ist keine gute Idee. Haben Sie beispielsweise überlegt, wie Sie Ihren Fork pflegen, wenn dynamische Importe hinzugefügt werden?
Auch gegen partielle Klassen wurden viele Argumente vorgebracht. Das Aufbrechen der Source-to-Source-Korrespondenz zwischen TypeScript- und JavaScript-Dateien widerspricht einem der wichtigsten Grundsätze der Sprache. Ich kann mir vorstellen, dass ein Feature ein Szenario ermöglichen müsste, das unendlich wertvoller ist als Teilklassen, damit das überhaupt berücksichtigt wird. Es würde wahrscheinlich trotzdem abgelehnt werden.

@WoLfulus , @cosmoKenney hat gut geantwortet. Um es mit Ihrer ersten Frage (zu A- und B-Dateien) besser zu machen: Als Sprachdesigner hat man das Privileg, Regeln zu definieren. Damit meine ich, dass Datei A einen solchen Code "Teilklasse X" und Datei B einen solchen Code "Teil(DateiX) Klasse X" haben kann, der fileX.js erzeugt.

Ich glaube nicht, dass Sie Ihre Botschaft rüberbringen. Das klingt so, als ob Sie das Gefühl haben, dass alle Einschränkungen, denen Sie jemals begegnen, wenn Sie sich in einer Sprache ausdrücken, aus völlig willkürlichen Gründen existieren.
Auch die Fragen von @WoLfulus wurden nicht beantwortet, zumindest nicht zu meiner Zufriedenheit.

zieht Flammenanzug an

TL;DR: Das passiert nicht. Wenn Sie hier unten bei Kommentar Nummer 189 sind und Ihre Ablehnung damit bekunden möchten, lesen Sie bitte zuerst den gesamten Thread, denn die sehr guten Gründe, dies nicht hinzuzufügen, wurden oben ausführlich behandelt.

Unsere Interpretation dieser Situation ist wie folgt:

  • TypeScript hat bereits zu viele TS-spezifische Klassenfunktionen (Konstruktor-Eigenschaftsdeklarationen, Member-Initialisatoren, nicht abgeschlossene Dekoratoren, Zugriffsmodifikatoren, implements usw.) für etwas, das eigentlich nur "ES6 + Typen" sein sollte. . Ein Teil davon ist unsere Schuld (unsere ursprüngliche Designrichtung war im Allgemeinen zu OOP) und ein Teil davon ist die Schuld von ES6 (der Klassenvorschlag hat sich vor fünf Jahren viel geändert und wir hatten Funktionen, die es nicht geschafft haben). Das Hinzufügen eines weiteren TS-spezifischen Klassenmerkmals ist ein weiterer Strohhalm auf dem Rücken des Kamels, den wir nach Möglichkeit vermeiden sollten.
  • Die Zukunft von JavaScript liegt eindeutig in den Modulen. Teilklassen machen nur Sinn und funktionieren gut im Modell "Globale Suppe". Das Zulassen von Teilklassen, die sich über mehrere Module erstrecken, ist ein Rezept für eine Katastrophe, da die Ladereihenfolge nicht vorhersehbar ist. Das Hinzufügen einer Funktion, die nur in einem rein globalen Universum gut funktioniert, ist keine gute Zeitverwendung.
  • C# hat es, aber wir sind nicht hier, um C# neu zu erfinden. Ernsthaft!
  • Das Szenario "generierter Code" ist nicht zwingend. Jede plausible Ausgabe für partielle Klassen würde die Eigenschaftsinitialisierer und den Konstruktorcode auf genau eine Deklaration beschränken, und dies wäre ein Dealbreaker für Setups im .Designer.cs Stil, da sowohl der Benutzercode als auch der generierte Code wahrscheinlich Initialisierer oder Konstruktorlogik benötigen würden .
  • Es gibt viele, viele andere Kompositionsmechanismen in JS - Mixins, Object.assign usw. Das Szenario, das zu dieser Funktion in C# führte, wurde durch Einschränkungen bestimmt, die in JS einfach nicht vorhanden sind.
  • Die aktuelle Problemumgehung von interface + prototype.method = ... nicht ermöglicht das generierten Code-Szenario genauso gut wie partial class würde. Es ist seltsam, diesen Code von Hand zu schreiben, aber es gibt kein Problem, Code anders zu generieren. Wenn Sie also wirklich glauben, dass ein Setup mit geteiltem Dateicode der einzige Weg ist, Ihr Problem zu lösen (ich bin skeptisch), dann steht Ihnen diese Methode zur Verfügung .
  • Wir betrachten ES6 als den „Must-have“ für den Unterricht. Es gibt nichts Besonderes an TypeScript (abgesehen von seiner Attraktivität für C#-Programmierer), die partielle Klassen ebensowenig benötigen wie nicht typisiertes JavaScript. Wenn es also ein Szenario gibt, das es wirklich aus dem Park schlägt, Teilklassen hinzuzufügen, dann sollte sich dieses Szenario durch den TC39-Prozess rechtfertigen können. Wenn das an Fahrt gewinnt, würden wir uns gerne mit Inputs dazu befassen, aber das scheint nicht einmal auf dem Radar von irgendjemandem zu sein.

@RyanCavanaugh dazu:

Die aktuelle Problemumgehung von interface + prototyp.method = ... ermöglicht das Szenario mit generiertem Code genauso gut wie eine partielle Klasse.

Wie ich mehr als einmal erwähnt habe, bin ich damit einverstanden, dass es eine nicht-partielle, nicht-c#-Methode gibt, um das zu erreichen, was ich brauche, und frage einfach nach einem funktionierenden Beispiel. David-driscoll war sehr hilfreich, hat aber Code gepostet, der sich nicht kompilieren lässt. Wenn Sie also denken, dass ich eine Klasse mit skalaren Eigenschaften nur für den Vor- und Nachnamen generieren kann - wie oben -, ist das in Ordnung. Ich brauche nur eine Möglichkeit, eine Sammlung anderer Typen als Eigenschaft der Klasse hinzuzufügen, indem ich das von Hand kodiere. Aber ich brauche auch eine Möglichkeit, die Initialisierung dieses Satzes zu handhaben.

@cosmoKenney ist

Es tut mir leid, das zu hören, aber ich respektiere die hier getroffenen Designentscheidungen. Ich habe ein paar Fragen, wenn das ok ist:

TypeScript hat bereits zu viele TS-spezifische Klassenfeatures (Konstruktor-Eigenschaftsdeklarationen, Member-Initialisatoren, nicht finalisierte Dekoratoren, Zugriffsmodifikatoren, Implements usw.) für etwas, das eigentlich nur "ES6 + Typen" sein sollte. Ein Teil davon ist unsere Schuld (unsere ursprüngliche Designrichtung war im Allgemeinen zu OOP) und ein Teil davon ist die Schuld von ES6 (der Klassenvorschlag hat sich vor fünf Jahren viel geändert und wir hatten Funktionen, die es nicht geschafft haben). Das Hinzufügen eines weiteren TS-spezifischen Klassenmerkmals ist ein weiterer Strohhalm auf dem Rücken des Kamels, den wir nach Möglichkeit vermeiden sollten.

Wäre in Anbetracht dessen ein möglicher Weg, organisatorisch und codetechnisch klar zwischen der reinen Typisierung von JS und den anderen Sprachkonstrukten, die TS bietet, zu unterscheiden? Ich für meinen Teil liebe sowohl das Tippen als auch die zusätzlichen Sprachfunktionen. Als Verbraucher/Entwickler ist es mir egal, dass der TS Dinge hinzufügt, die in JS nicht vorhanden sind. Gib mir einfach geiles Zeug, wenn TC39 es nicht will, ist mir egal.

Wenn TS diese Dinge voneinander kapseln würde, wäre das vielleicht einfacher wiederzuverwenden und würde von Projekten wie SoundScript abgespalten und darauf aufgebaut, anstatt ersetzt zu werden?

Und dann könnten andere Projekte auf dieser Typisierung aufbauen, um bessere/andere Sprachkonstrukte bereitzustellen, als sie von JS angeboten werden.

Die Zukunft von JavaScript liegt eindeutig in den Modulen. Teilklassen machen nur Sinn und funktionieren gut im Modell "Globale Suppe". Das Zulassen von Teilklassen, die sich über mehrere Module erstrecken, ist ein Rezept für eine Katastrophe, da die Ladereihenfolge nicht vorhersehbar ist. Das Hinzufügen einer Funktion, die nur in einem rein globalen Universum gut funktioniert, ist keine gute Zeitverwendung.

Ist das wirklich? Sicher, dass Module ein natürlicher Bestandteil von JavaScript wären, aber was ist mit dem ursprünglichen Hauptcode? Ich liebe Namensräume und es gibt keine Suppe darin, wenn es richtig gemacht wird. Ich kompiliere alles in eine Datei und benötige keine Modullader und in fast allen Fällen kein asynchrones Laden von Modulen. Einige Vorschläge wie https://github.com/Microsoft/TypeScript/issues/420 wären nur mit Namespaces möglich und relevant. Wollen Sie damit sagen, dass so etwas nicht passieren wird, weil wir nur Module verwenden sollten? Sind Namespaces auf dem Weg zur Veraltung?

@david-driscoll Danke, du warst schon hilfreich genug. Da @RyanCavanaugh derjenige ist, der das Problem immer wieder schließt und angibt, dass es Problemumgehung bereitstellen.

Ich sehe auch viele Missverständnisse darüber, was Teilklassen sind. Es ist wirklich ein einfaches Konstrukt, und jeder bläst dies überproportional:
https://msdn.microsoft.com/en-us/library/wa80x488.aspx

Wäre in Anbetracht dessen ein möglicher Weg, organisatorisch und codetechnisch klar zwischen der reinen Typisierung von JS und den anderen Sprachkonstrukten, die TS bietet, zu unterscheiden? Ich für meinen Teil liebe sowohl das Tippen als auch die zusätzlichen Sprachfunktionen. Als Verbraucher/Entwickler ist es mir egal, dass der TS Dinge hinzufügt, die in JS nicht vorhanden sind. Gib mir einfach geiles Zeug, wenn TC39 es nicht will, ist mir egal.

Das wäre ein Umschreiben einer Sprache und würde jedermanns Code brechen.

Auch das "Gib mir einfach tolle Sachen" unterscheidet sich grundlegend von den Designzielen für TypeScript . Wenn Sie einfach nur tolle Sachen wollen und sich nicht um die Ausrichtung an JavaScript kümmern, sollten Sie eine andere Sprache wie CoffeeScript , Dart oder Haxe wählen. Natürlich gibt es vielleicht Gründe, warum diese nicht so gut abschneiden wie TypeScript in der Einführung...

jemand, der das Thema immer wieder schließt und angibt, dass es Workarounds gibt, sollte er vielleicht ein Beispiel für Workarounds geben

Es gibt viele Anwendungsfälle für das, was ein partial löst. Fast jedes Sprachkonstrukt hat viele Anwendungsfälle, für die es gültig ist, aber aus guten Gründen müssen Sie auswählen.

Sie fragen immer wieder nach einer bestimmten Sprachfunktion, wie in "Ich würde ein grünes Auto lieben", kommen aber nicht zum Kern des Problems. Warum muss das Auto grün sein? Wenn Sie erklärt haben, warum Ihr Auto grün sein muss, oder offen dafür sein, dass es Ihnen eigentlich egal ist, welche Farbe Ihr Auto hat, solange es Ihren tatsächlichen Bedürfnissen entspricht.

Ich verstehe nicht, warum Sie Ryans Verpflichtung sehen, Ihnen zu sagen, wie Sie Ihr Auto neu lackieren müssen, nur weil die Autofirma aus triftigen Gründen beschlossen hat, keine umweltfreundlichen Autos zu produzieren.

(Oh, und die Mixin-Klassen, die in TypeScript 2.2 hinzugefügt wurden, sind eine gute Möglichkeit, das zu erreichen, was ich vermute, dass Sie wirklich brauchen)

interface Base {}

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

interface PartialClass {
    foo(): void;
}

function PartialClass<B extends Constructor<Base>>(base: B): B & Constructor<PartialClass> {
    return class extends base {
        foo() {
            console.log('foo');
        }
    };
}

class MyBase {
    bar() {
        console.log('bar');
    }
}

const MyPartialBase = PartialClass(MyBase);

const instance = new MyPartialBase();

instance.bar();
instance.foo();

@kitsonk- Mixins sind nicht dasselbe.

  • Mixins sind in sich geschlossene Einheiten, die zu bestehenden Klassen hinzugefügt werden können.
  • Partielle Klassen können auf Member von jedem anderen partiellen zugreifen, als ob sie Teil derselben Klasse wären.

Versuchen Sie als Übung den folgenden Code-Split mit Mixins zu implementieren:

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

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

Versuchen Sie als Übung den folgenden Code-Split mit Mixins zu implementieren

Also zurück zum Punkt... Welches Problem versuchen Sie mit Ihrem Beispiel zu lösen, anstatt auf eine Sprachfunktion hinzuweisen? Weil die Problemumgehung in TypeScript einfach ist:

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

(und wenn wir vollständig sind, aber auch hier löst es eine Anwendung, nicht alle Anwendungsfälle)

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);

@Elefanten-Schiff

Wäre in Anbetracht dessen ein möglicher Weg, organisatorisch und codetechnisch klar zwischen der reinen Typisierung von JS und den anderen Sprachkonstrukten, die TS bietet, zu unterscheiden?

Ich sehe derzeit keine Möglichkeit, die beiden zu entwirren. Theoretisch könnte man eine Sprache ala CoffeeScript schreiben, die sich syntaktisch in TypeScript verwandelt, und diese höhere Sprache verwenden, um neue syntaktische Funktionen hinzuzufügen, während man weiterhin das Typsystem von TS verwendet, aber das würde Sie nur so weit bringen. Es scheint die bessere Wahl zu sein, sich stattdessen für eine der vielen anderen Greenfield-Kompilierungssprachen in JS zu entscheiden, wenn dies das Ziel ist.

Wollen Sie damit sagen, dass so etwas nicht passieren wird, weil wir nur Module verwenden sollten? Sind Namespaces auf dem Weg zur Veraltung?

Namespaces gehen sicher nirgendwo hin. Sie sind nur eine Benennung eines Musters, das bereits weit verbreitet ist und in einer Welt der ES6-Module immer noch viel Sinn macht. Module sind immer mehr die Art und Weise, wie Menschen ihren Code organisieren, und sie haben viele großartige Nebenvorteile. Ich sage nur, dass Teilklassen in dieser Welt fast keinen Sinn machen, und es wäre seltsam, ein grundlegend neues Organisationsmuster hinzuzufügen, das damit nicht kompatibel ist. Wenn sich die Welt in die entgegengesetzte Richtung bewegen würde und alle sagen würden: "Globale Skripte mit Nebenwirkungen beim Laden sind großartig, jeder feiert auf den prototype s des anderen", würden wir vielleicht anders denken.

@RyanCavanaugh

Vielleicht ja ... Vielleicht machen sie nicht so viel Sinn ... Aber wie ich schon oft gesagt habe, ich denke, sogar in diesem Thread geht es bei Teilklassen darum, die Codegenerierung zu vereinfachen ... Das ist der Hauptvorteil, den ich sehe von ihnen lohnt sich das Feature in TS... Ich, und ich muss von vielen anderen ausgehen, aber das ist nur eine Vermutung, erzeuge derzeit Tonnen von TS-Code aus meinem C#-Code... Aber dann stellt sich die Frage, wie man den generierten sicher erweitern kann TS-Code??? Diese Frage ist mit Teilklassen viel einfacher zu beantworten... Derzeit greifen wir auf Hacks zurück, um benutzerdefinierten Code in unseren generierten TS-Codedateien zu behalten...

Vielen Dank

Genauso generieren wir hier den Typoskript-"Proxy" für unsere C#-APIs und möchten diese Objekte einfach in Typoskript erweitern können.

Ich bin kein JS-Spezialist, also muss mir etwas fehlen, denn ich sehe nicht, warum es so sein sollte, die Deklaration von Klassen in mehrere TS-Dateien (mit nur einer Klassendeklaration in nur einer JS-Datei nach der Kompilierung) aufzuteilen ein Problem für die JS-Welt. Soweit ich das sehe, ist es für JS transparent, als wäre es von Anfang an in eine Datei geschrieben worden. Ich meine, ob Sie Teilklassen verwenden oder nicht, die JS-Ausgabe wird genau gleich sein, aber sie verhindert die Kosten der JS-Objekterweiterbarkeit für unsere Entwickler.

@RyanCavanaugh

Eine andere Sache, die ich erwähnen wollte, dass ich persönlich den TS-Compiler nicht auffordere, irgendwie das Verpackungsdilemma zu lösen, das beim Erstellen eines ES6-Moduls mit Teilklassen in verschiedenen TS-Dateien auftreten könnte... Kompilieren mehrerer TS-Dateien in eine einzige js-Datei für das ES6-Modul ... Auch hier helfen partielle Klassen erheblich bei der Codegenerierung ... Sie ermöglichen es Tools, große Teile Ihres Modells mit zuverlässiger Erweiterbarkeit zu erstellen ...

@kitsonk

Sie fragen immer wieder nach einer bestimmten Sprachfunktion, wie in "Ich würde ein grünes Auto lieben", kommen aber nicht zum Kern des Problems. Warum muss das Auto grün sein? Wenn Sie erklärt haben, warum Ihr Auto grün sein muss, oder offen dafür sein, dass es Ihnen eigentlich egal ist, welche Farbe Ihr Auto hat, solange es Ihren tatsächlichen Bedürfnissen entspricht.

Nein, ich frage nicht mehr nach einer neuen Funktion. Es wurde immer wieder gesagt, dass die Sprache das erreichen kann, was ich will. Ich habe Beispiele für das bereitgestellt, was ich will (in C#), aber ich muss in den hilfreichen Beispielen noch einen Weg sehen, um dorthin zu gelangen, wo ich sein muss.

Ich verstehe nicht, warum Sie Ryans Verpflichtung sehen, Ihnen zu sagen, wie Sie Ihr Auto neu lackieren müssen, nur weil die Autofirma aus triftigen Gründen beschlossen hat, keine umweltfreundlichen Autos zu produzieren.

Ryan scheint hier Moderator zu sein und schließt das Thema. Deshalb. Wenn er eine Sprachbehörde ist, sollte er das Problem vielleicht nicht abschließen, bevor er sich bemüht hat, mein Anliegen zu verstehen und diese Anfrage ablehnt, ohne ein Beispiel dafür zu geben, wie dies mit muttersprachlichen Funktionen geht. Ich habe angegeben, dass ich eine Lösung zur Kompilierzeit möchte. Und ich bin ein ziemlich guter Entwickler und programmiere schon seit einiger Zeit in vielen verschiedenen und obskuren Sprachen, und ich tue mir immer noch sehr schwer mit der Mixin-Syntax. Ich verstehe nicht, wie etwas so Komplexes und Schwer Verständliches in die Sprache gelangt ist, und dennoch lehnt jeder die Eleganz der partiellen Klassensyntax ab, einfach, wie es scheint, weil sie von C# übernommen wurde.

Ryan scheint hier Moderator zu sein und schließt das Thema. Deshalb. Wenn er eine Sprachbehörde ist, sollte er das Thema vielleicht nicht abschließen, bevor er sich bemüht, mein Bedürfnis zu verstehen

🤔

@RyanCavanaugh , ich weiß, dass Sie sich bemüht haben zu helfen. Und an diesem Punkt gehe ich dazu über, Mixins auszuprobieren. Oder nur Vererbung, oder vielleicht habe ich es so eilig, dieses Projekt fertigzustellen, dass ich eine Möglichkeit übersehe, dies mit Generika zu tun. Hmm...
Mit Vererbung und Benennung kann ich Folgendes tun:

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 ) );
        }
    }
}

Und das funktioniert bei mir gut. Es ist nicht so schön und zwingt meine durch Code generierten Klassen, Namen zu haben, die ich nicht im Code verwenden möchte. Aber es funktioniert wieder.

Im Moment habe ich das Gefühl, dass Leute, die stark gegen partielle Klassen sind, das Konzept der partiellen Klassen einfach falsch verstehen und denken, dass partielle Klassen etwas sind, was partielle Klassen nicht sind.

Um es klar zu machen: Eine partielle Klasse ist eine syntaktische Konstruktion, mit der Sie die Definition einer einzigen Klasse in mehrere physische Dateien aufteilen können. Schlüsselwörter sind hier "gleich" und "einzeln".

Die Dokumentation von TypeScript enthält eine schlechte Definition von Teilklassen (erster Absatz hier: https://www.typescriptlang.org/docs/handbook/mixins.html ).

Beispiel für das Konzept der realen Teilklassen:

Datei "Point.generated.ts":

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

Datei "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);
  }
}

Sie kompilieren in "Point.js" - und der Name kommt aus dem Namen einer Klasse, nicht aus den Namen von Dateien:

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, wenn sie als "partielle Klassen" verwendet werden (und ich bin fest davon überzeugt, dass dieser Begriff in der Dokumentation missbraucht wird ), stellen tatsächlich eine Mehrfachvererbung dar ( https://en.wikipedia.org/wiki/Multiple_inheritance ).

Wie wir sehen, diskutieren wir also zwei verschiedene Werkzeuge: echte partielle Klassen und Mehrfachvererbung. Das sind zwei verschiedene Werkzeuge. Und wie jedes Werkzeug haben sie ihren eigenen Anwendungsbereich. Mit anderen Worten: Ein Zimmermann kann statt eines Hammers auch einen Hammer verwenden, wenn der Hammer nicht zur Verfügung steht, der Hammer aber nicht das richtige Werkzeug ist.

IMHO, diese Diskussion hat keine Zukunft und wir sollten sie beenden. Während ich für echte Teilklassen noch keine technologischen Probleme sehe, hat das Team zumindest vorerst keine Lust, diese umzusetzen.

Das TS-Team möchte nach Möglichkeit keine TS-spezifischen Features implementieren. Wenn Sie mehr diskutieren möchten, dann ist hier ein besserer Ort: https://esdiscuss.org/topic/class-syntax-enhancements

Ich hoffe, es gibt ein GitHub-Repo auf der TC39-Seite , um diese Dinge zu diskutieren, anstatt ein Mailing-basiertes :/

@greendimka

Im Moment habe ich das Gefühl, dass Leute, die stark gegen partielle Klassen sind, das Konzept der partiellen Klassen einfach falsch verstehen und denken, dass partielle Klassen etwas sind, was partielle Klassen nicht sind.

Um es klar zu machen: Eine partielle Klasse ist eine syntaktische Konstruktion, mit der Sie die Definition einer einzigen Klasse in mehrere physische Dateien aufteilen können. Schlüsselwörter sind hier "gleich" und "einzeln".

Ich glaube nicht, dass irgendjemand hier die Definition von Teilklassen missversteht, ich denke, Sie missverstehen vielleicht die Definition von Klassen in JavaScript.

Wenn Sie den Eindruck haben, dass JavaScript-Klassen den Klassen praktisch jeder anderen weit verbreiteten Sprache ähneln, dann _scheint_ Ihnen vielleicht, dass andere andere Missverständnisse haben.

Wie jedoch in dieser Diskussion mehrmals gesagt wurde, weiß ich, dass ich es mindestens einmal explizit gesagt habe, JavaScript-Klassen sind keine deklarativen Konstrukte, sondern zwingend erforderlich.

Sie existieren erst, wenn Anweisungen ausgeführt werden.

Ihre Definition beruht auf Mutation.

Das macht sie schon bei der Vererbung brüchig und ordnungsabhängig.

Das könnte so weitergehen...

@cosmoKenney

Ich verstehe nicht, wie etwas so Komplexes und Schwer Verständliches in die Sprache gelangt ist, und dennoch lehnt jeder die Eleganz der partiellen Klassensyntax ab, einfach, wie es scheint, weil sie von C# übernommen wurde.

Das finde ich wirklich nicht richtig. Jeder liebt C#, sogar Java-Programmierer 😛, und TypeScript ist nicht anders, um anders zu sein.

@aluanhaddad

Ich glaube, du verstehst vielleicht die Definition von Klassen in JavaScript falsch...

Für zitiert und unten: Ich spreche vom TypeScript.
Wie gesagt: Ich sehe kein technisches Problem darin, echte partielle Klassen in TypeScript zu implementieren, die in JavaScript-Konstrukte kompiliert werden.

@greendimka

Für zitiert und unten: Ich spreche vom TypeScript.
Wie gesagt: Ich sehe kein technisches Problem bei der Implementierung echter partieller Klassen in TypeScript, die in JavaScript-Konstrukte kompiliert werden.

Das Problem mit dieser Aussage, es gibt keine TypeScript-Klasse.

Oh Junge! Manche Leute werden alles als Grund verwenden.
Ok, es gibt keine Klassen in TypeScript. Oder TypeScript-Klassen. Oder Wasauchimmer. Wie auch immer.

Ich meine, dass es sich um JavaScript-Klassen handelt. Obwohl ich manchmal pedantisch bin, mache ich diese Unterscheidung ganz konkret, weil wir uns auf die Definition des Begriffs Klasse einigen müssen, bevor wir diskutieren können, welche Funktionen einfach hinzugefügt werden können.

Ich denke, wir meinen nicht dasselbe, wenn wir von Klassen sprechen, und das führt zu kognitiven Dissonanzen und behindert das gegenseitige Verständnis.

Ich denke, wir meinen nicht dasselbe, wenn wir von Klassen sprechen, und das führt zu kognitiven Dissonanzen und behindert das gegenseitige Verständnis.
Stimme voll und ganz zu!

Tatsächlich beschreibt der erste Beitrag in diesem Thema perfekt, was gewünscht wurde, daher hat diese Diskussion keine Zukunft :)

@greendimka ja, es hat keine Zukunft, da TypeScript anscheinend nie

Missverständnisse und Missverständnisse sind jedoch keine guten Dinge, weshalb ich mich immer noch mit Ihnen unterhalte.

Leider scheint dich das auch nicht zu interessieren

A. Wenn Sie erklären, was JavaScript Klassen sind, könnten Sie Ihre Meinung ändern und Ihnen zustimmen, dass sie trivialerweise partiellisierbar gemacht werden können.

B. Von anderen lernen, was JavaScript-Klassen sind, damit Sie den gegensätzlichen Standpunkt verstehen müssen.

Ich finde das schade, aber ich werde es nicht weiter diskutieren, wenn Sie es wünschen.

Ich bin nicht gegen Diskussionen. Aber hier wurde schon mehrfach darauf hingewiesen, dass Teilklassen nicht implementiert werden (zumindest jetzt nicht). Daher denke ich, dass es besser ist, sich auf andere Dinge zu konzentrieren. Vielleicht kann TypeScript in Zukunft geändert werden, wer weiß.
In Bezug auf A und B. Ich hasse JavaScript. Aber ich kenne es sehr gut und weiß natürlich, wie Klassen darin "dargestellt" werden. Aber der Sinn dieser ganzen Diskussion bestand nicht darin, JavaScript zu modifizieren, sondern die Fähigkeiten von TypeScript als einer höheren Sprache zu verbessern, die JavaScript-Code auf niedriger Ebene erzeugt.
Stellen Sie sich vor, wir würden TypeScript durch C++ und JavaScript durch Maschinencode ersetzen. Im Maschinencode fehlen die meisten Konzepte, die in C++ existieren. Aber sollte C++ deswegen aufhören, sich weiterzuentwickeln? Natürlich nicht. Sollte es aufhören, sich weiterzuentwickeln, weil einige alte Compiler nicht kompilieren können? Natürlich nein - Sie geben Entwicklern ein neues Feature und sagen ihnen: es funktioniert mit neuen Compilern - Sie (Entwickler) entscheiden, ob Sie es verwenden möchten.

@aluanhaddad
Mann oh Mann. Wen interessiert der Javascript-Teil der Gleichung? TypeScript ist eine Ebene darüber, oder wie Sie es formulieren möchten. Erinnern Sie sich an die alten Diskussionen zwischen 4GL und 3GL? TypeScript ist für Javascript wie 4GL für 3GL. Auch das Argument, dass TypeScript ES6 mit starken Typen ist, also Partial Classes außerhalb des Geltungsbereichs der Roadmap von TypeScript liegt, ist LAME. Wir haben Mixins, Generics, Modules, Namespaces und Type Casting. Warum also nicht mit Teilklassen die Extrameile gehen?

Von partiellen Klassen wollen wir nur den syntaktischen Zucker, der es uns ermöglicht, alle verschiedenen Definitionen einer einzelnen TypeScript-Klasse zu einer endgültigen - Low-Level - 3GL - Javascript-Klassendefinition zusammenzufassen. Es sollte keine Auswirkungen auf die endgültige JavaScript-Klassendefinition haben, oder? Warum ist das Endprodukt der Transpilation in Javascript überhaupt Teil dieser Diskussion? Ernsthaft.

@cosmoKenney "es ist nur ES.next mit Typen" ist ein großes Verkaufsargument, das JavaScript-Entwickler umwandelt. Wenn Sie etwas mehr wollen, suchen Sie die falsche Sprache. Vielleicht versuchen Sie es stattdessen mit

edit: Ich hatte gerade eine interessante Erkenntnis, dass in ES.next Teilklassen mit einem benutzerdefinierten Modullader implementiert werden können. Wenn du benutzt

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

der Loader könnte alle exportierten MyClass-Definitionen aus allen Dateien, die dem Platzhalter entsprechen, in einer einzigen Klasse zusammenführen und diese dann bereitstellen.

@spion Ich mag, wie Sie sie ganz richtig als ES.next-Teilklassen bezeichnen. Ein ES-Modullader wie ein Browser oder ein Loader-Polyfill wie SystemJS würde dann Teilklassen unterstützen.
Eines der Hauptprobleme beim Hinzufügen dieser Funktion auf TypeScript-Ebene besteht darin, dass vorhandene Tools wie Loader und Packager beschädigt werden. Auf der anderen Seite, wenn ECMAScript sie spezifiziert, dann würden alle diese Tools die Funktion implementieren und TypeScript würde mit all diesen Tools kompatibel bleiben.

In Bezug auf Scala.js stimme ich dir definitiv zu

@cosmoKenney

Wir haben Mixins, Generics, Modules, Namespaces und Type Casting. Warum also nicht mit Teilklassen die Extrameile gehen?

Mixins, wie sie in TypeScript zu sehen sind, sind ein ECMAScript-Entwurfsmuster, das TypeScript _types_.

Generics sind eine Typsystemfunktion und gelten daher nicht.

Module sind eine ECMAScript-Funktion.

Namespaces sind ein syntaktischer Zucker für und eine Formalisierung eines ECMAScript-Entwurfsmusters.

Typumwandlung ist in TypeScript nicht vorhanden.

@aluanhaddad warum machst du das immer wieder zur Laufzeit? Modullader und all das hat nichts mit Transpilieren zu tun.

+1

@cosmoKenney

@aluanhaddad warum machst du das immer wieder zur Laufzeit? Modullader und all das hat nichts mit Transpilieren zu tun.

Das ist nicht richtig.

Schauen Sie sich die SystemJS- und Webpack-Ökosysteme an und Sie werden etwas anderes sehen.

Noch traditionellere und grundsolide Arbeitsabläufe basieren auf der Korrespondenz zwischen Eingabe- und Ausgabedateien.

+1

Ich brauche eine partielle Klasse, weil wir den größten Teil der Basisklasse mit Tools generieren (um zu automatisieren, wenn sich das Modell ändert). Wir verwenden dann die partielle Klasse, um der Klasse Funktionen in separaten Dateien hinzuzufügen, damit sie nicht vom Tool (das die Klasse automatisch generiert) überschrieben wird.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

dlaberge picture dlaberge  ·  3Kommentare

jbondc picture jbondc  ·  3Kommentare

siddjain picture siddjain  ·  3Kommentare

manekinekko picture manekinekko  ·  3Kommentare

kyasbal-1994 picture kyasbal-1994  ·  3Kommentare