Typescript: Unterstützen Sie die vorgeschlagenen ES Rest/Spread-Eigenschaften

Erstellt am 21. Feb. 2015  ·  96Kommentare  ·  Quelle: microsoft/TypeScript

es7-Vorschlag: https://github.com/sebmarkbage/ecmascript-rest-spread

Spread-Eigenschaften

Tippen

Meiner Meinung nach besteht das Ziel dieser Methode darin, ein Objekt duplizieren und einige Requisiten ändern zu können. Daher halte ich es in diesem Fall für besonders wichtig, die doppelte Eigenschaftsdeklaration nicht zu überprüfen:

var obj = { x: 1, y: 2};
var obj1 = {...obj, z: 3, y: 4}; // not an error

Ich habe einen sehr naiven Typprüfungsalgorithmus für ein ähnliches Feature ( JSXSpreadAttribute ) in meiner kleinen jsx-typescript Gabel: Ich kopiere einfach die Eigenschaften des _Spread-Objekts_ in die Eigenschaftstabelle, wenn ich auf ein Spread-Objekt stoße , und überschreiben Sie diese Eigenschaft, wenn ich auf eine Deklaration mit einem ähnlichen Namen stoße.

Ausstrahlen

jstransform use Object.assign , babel führt ein Shim ein:

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

Wir könnten entweder das Vorhandensein der Funktion assign auf der Schnittstelle ObjectConstructor erzwingen oder eine ähnliche Funktion (mit einem anderen Namen) bereitstellen.

Ich denke, die optimale Lösung wäre, keinen Helfer im Ziel es6 auszugeben (oder wenn Object.assign definiert ist) und eine Helferfunktion für es5 , es3 .

var obj = { x: 1, y: 2};
var obj1 = {...obj, z: 3};

/// ES6 emit
var obj = {x: 1, y: 2};
var obj1= Object.assign({}, obj, { z: 3 });

//ES3 emit
var __assign = function (target) { 
    for (var i = 1; i < arguments.length; i++) { 
        var source = arguments[i]; 
        for (var key in source) { 
            if (Object.prototype.hasOwnProperty.call(source, key)) { 
                target[key] = source[key];
            } 
        } 
    } 
    return target; 
};

var obj = {x: 1, y: 2};
var obj1= __assign({}, obj, { z: 3 });

Ruheeigenschaften

Tippen

Für einfache Objekte ist der neue Typ ein Untertyp der Zuweisung, der keine Eigenschaften enthält, die vor den restlichen Eigenschaften erfasst wurden:

var obj = {x:1, y: 1, z: 1};
var {z, ...obj1} = obj;
obj1// {x: number; y:number};

Wenn die destrukturierende Zuweisung eine Indexdeklaration hat, hat das Ergebnis auch eine ähnliche Indexdeklaration:

var obj: { [string: string]: string };
var {[excludedId], ...obj1} = obj;
obj1// { [string: string]: string };

new/call-Deklarationen werden offensichtlich nicht erfasst:

var obj: { (): void; property: string};
var { ...obj1} = obj;
obj1// { property: string };

Ausstrahlen

Es ist nicht möglich, _rest properties_ ohne eine Hilfsfunktion auszugeben, diese ist von babel:

var obj = {x:1, y: 1, z: 1};
var {z, ...obj1} = obj;
var __objectWithoutProperties = function(obj, keys) {
    var target = {};
    for (var i in obj) {
        if (keys.indexOf(i) >= 0) continue;
        if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
        target[i] = obj[i];
    }
    return target;
};

var obj = {x:1, y: 1, z: 1};
var z = obj.z;
var obj1 = __objectWithoutProperties(obj, ["z"]);

_Edit: ein kleines Tipp-/Ausgabebeispiel hinzugefügt_

Committed ES Next Fixed Suggestion

Hilfreichster Kommentar

Ich bin mir nicht sicher, wie wir es letztendlich versenden werden, aber ich habe mit der Arbeit an Rest/Spread in Objektliteralen und Destrukturierung begonnen . Im Moment ist der Plan, unser Polyfill __assign Emittieren zu verwenden.

Alle 96 Kommentare

Wir bräuchten wahrscheinlich einige Beispiele dafür, wie dies in einem Downlevel plausibel ausgegeben werden könnte (wenn dies im Umfang ist).

@RyanCavanaugh , ich habe ein kleines emittierendes Beispiel und eine
Ich würde gerne daran arbeiten, da es sowieso mehr oder weniger ein jsx-Feature ist und ich es zu meinem Fork hinzufügen muss, aber wenn es zum Typoskript-Kern hinzugefügt wird, ist es besser ^^.

Ich habe diese Funktion in ES7 kürzlich über diesen Artikel entdeckt . Ich muss sagen, es ist ganz praktisch!

Würde das gerne in TypeScript sehen!

Irgendwelche Updates dazu? Würde das gerne in 1.6 sehen, da es bei der Verwendung mit React super praktisch wäre :smile:

@prabirshrestha fürs Protokoll, wir haben derzeit den Property-Spread-Operator für JSX auf master .

@DanielRosenwasser Könntest du das Ruheeigenschaften oder nur Streueigenschaften ?

Sorry @mnpenner und @prabirshrestha , ja, ich meinte auf master . @RyanCavanaugh weiß mehr darüber als ich, aber ich glaube, es sind nur Spread-Eigenschaften.

JSX unterstützt verbreitete _Attribute_, zB <TagName {...spreadedExpr} /> . Nichts hat mit dem ES6-Spread-Operator zu tun, außer dass er denselben Token teilt und eine ungefähr gleiche Semantik hat.

Ich interessiere mich sowohl für Redux als auch für React, die Manipulation im Zustand wird damit viel einfacher. Würde das gerne umgesetzt sehen.

Rest/Spread ist jetzt für Stage 2 freigegeben https://github.com/tc39/tc39-notes/blob/master/es7/2015-07/july-30.md

Wir wollen warten, bis der Vorschlag Stufe 3 erreicht, bevor wir uns damit befassen.

Es ist sehr nützlich in Reagieren und Reduxen, bitte implementieren Sie es so schnell wie möglich, bitte :-)

Hier ist ein Hilfsmodul, das ich verwendet habe, um dies zu umgehen. Es ist nicht ideal, da Sie alle Tasten zweimal angeben müssen, einmal auf der linken Seite und einmal als Saiten auf der rechten Seite, aber ich kann mir keinen besseren Weg vorstellen. Jedes Feedback ist willkommen, ich bin mir sicher, dass ich ein Edge-Verhalten übersehen habe!

https://gist.github.com/tomduncalf/fbae862b123445c117cb

Ist das etwas, wofür Sie einen Patch akzeptieren würden? (wird zusammengeführt, sobald es Stufe 3 erreicht hat). Und wenn ja, haben Sie Hinweise, wo Sie anfangen sollten, Änderungen vorzunehmen, um dies zu unterstützen?

Dies ist die letzte ES7+-Funktion, die mein Team intensiv nutzt und die uns daran hindert, auf Typoskript umzusteigen. würde es auf jeden Fall gerne früher tun, wenn möglich.

Wir würden hier eine PR in Erwägung ziehen. Beachten Sie jedoch, dass die Verkabelung des Typsystems für diese Funktion keine einfache Aufgabe ist. Wenn Sie daran interessiert sind, dies zu lesen, würde ich es inkrementell halten und mit dem Parsen beginnen, dann die Überprüfung ausgeben und dann eingeben. @sandersn sollte Ihnen bei Fragen helfen können.

Nur eine Anmerkung für diejenigen, die daran interessiert sind, dies mit Redux zu verwenden. Ich stimme zu, dass die Notation bequem ist. Aber ich bin eigentlich auch ohne ausgekommen, indem ich die updeep Bibliothek genutzt habe. Ich habe einige grundlegende Eingaben dafür erstellt und es funktioniert ziemlich gut. Ich habe sogar eine einfache Bibliothek, die einen updeep basierten Speicher und Aktionen implementiert. Falls jemand Interesse daran hat, meldet euch einfach bei mir.

In jedem Fall :+1: für Spread-Operatoren in TS. :Lächeln:

@xogeny Ich wäre sehr daran interessiert, mir diese Bibliothek anzusehen. Danke

@cur3n4 Ich habe ein Repository, in dem ich mit diesen Ideen gespielt habe. Es ändert sich ziemlich viel (da sich das alles noch weiterentwickelt). Ich habe ein spezielles Modul verwendet, das anfangs updeep nutzte und diese Funktionalität immer noch in der Bibliothek ist . Aber ich habe aufgehört, es zu verwenden, weil ich es schwierig fand, die erforderlichen Typeinschränkungen beizubehalten. Ich vermute, dass updeep (und mehrere andere Bibliotheken, wie lodash oder ramda ) sein könnten, wenn Typescript etwas in der Art von Javas super generischen Typbeschränkungen hätte machte viel mehr typsicher.

Aber verstehen Sie mich nicht falsch, ich denke immer noch, dass ein Spread-Operator wirklich nützlich wäre. Es würde Ihnen tatsächlich ermöglichen, Dinge sicher und knapp in der Sprache auszudrücken und zu tun, die ich mit dem aktuellen Typsystem nicht machen kann (_d. Im Moment opfere ich die Knappheit der Sicherheit (während der updeep Ansatz die Sicherheit der Knappheit geopfert hat).

Nachdem ich Babel in den letzten Monaten benutzt hatte, konvertierte ich mein Projekt in TS und musste all dies wiederholen. Würde das gerne umgesetzt sehen!

:+1:

würde das gerne sehen.

+1

muss Funktion haben, bitte implementieren

+1

+1 viel schönere Syntax als Object.assign + JSX-Unterstützung

+1 Es ist ein Muss für die Entwicklung von Reaktionen, um Requisiten weiterzugeben ( var { checked, ...other } = this.props; . Siehe die Reaktionsdokumente

es ist ein Muss für die Reaktionsentwicklung

Seien wir ehrlich, es ist eine Annehmlichkeit, kein Muss. Der Vorschlag befindet sich in Phase 2 mit TC39. Das TypeScript-Team hat klargestellt, dass es nicht in Erwägung ziehen möchte, Dinge zu implementieren, die nicht in TypeScript entstanden sind, bis sie Stufe 3 sind. Der Ort für "+1" ist bei TC39.

@kitsonk - Sie können keine gute Akzeptanz erwarten, wenn Frameworks wie Reagieren / etc. diese Art von Dingen in ihren Dokumenten speziell hervorheben. Die Leute werden anfangen, Typescript zu verwenden, all diese Probleme sehen und zu Babel zurückkehren. Das ist, was ich tat.

Nun, ich denke, wir sprechen über ein breiteres Thema. Kein einziger Browseranbieter wird etwas implementieren, das nicht in Phase 3 enthalten ist (es sei denn, es gefällt ihm persönlich). TC39 hat versucht, seinem Teil des Webs ein gewisses Maß an Organisation zu verleihen. TypeScript wurde schon zuvor massiv gebissen, indem es mit der Waffe gesprungen ist (Module, und schauen Sie sich das Chaos an, das seitdem verursacht hat). Ich respektiere, dass sie versuchen, zumindest eine Anleitung und Struktur zu geben, was sie wann umsetzen wollen. Gibt es einen anderen Vorschlag, welcher Standard verwendet werden sollte? Ich glaube nicht, dass "weil das X-Framework es in seinen Dokumenten erwähnt" gut wäre.

Frameworks wie Reagieren / etc. nennen diese Art von Dingen in ihren Dokumenten spezifisch

Was sie nur als Vorschlag markieren und Ihnen dann zeigen, wie Sie durch die Reifen springen, um Babel 6 für die Verwendung zu konfigurieren. Ich würde eher Frameworks dafür verantwortlich machen, dass sie von syntaktischen Technologien abhängen, die nur in einer Entwurfsspezifikation enthalten sind. Persönlich wurden wir im Dojo von Object.observe verbrannt und ich bin wieder zurückhaltend, um zu versuchen, mich auf Technologien zu verlassen, bevor sie Stufe 3 in Dojo erreichen.

Der spezielle Pfad ist viel mehr als nur die Unterstützung der Transformation der Syntax beim Emit für TypeScript. Es gibt alle Typeninferenzen, die darauf folgen müssen. Ich habe mir den Entwurf der Spezifikation angeschaut, um das zu verstehen, aber wohin gehen die Symbole? Wohin gehen nicht aufzählbare Eigenschaften? Ich gehe davon aus, dass sie in beiden Fällen einfach im Äther verschwinden, aber es wird alle Arten von Typaufspaltung und -zusammenführung geben, die dafür im Hintergrund ablaufen müssen, daher kann ich das TypeScript-Team total verstehen, das sagt "OK, lass uns warten" darauf, bis TC39 wirklich auf die Reifen getreten hat".

Insgesamt denke ich, dass TS heute recht gut präsentiert wird. Es gab eine Zeit (ungefähr 1,4 ~ 1,5, glaube ich), in der ich durch das Fehlen einiger ES2015-Funktionen frustriert war, aber bis heute hat TS den Standard ziemlich gut eingeholt.

Natürlich gibt es manchmal Feature-Neid gegenüber anderen Sprachen. Babel bietet zum Beispiel so ziemlich jeden JS-Vorschlag, einschließlich "experimenteller" Sachen. Persönlich freue ich mich auf dieses Problem und auch auf den Bindeoperator der Funktion.

Aber gleichzeitig müssen wir anerkennen, dass das TS-Team die Kompatibilität viel ernster nimmt als Babel. Sie möchten nicht die Semantik Ihres Codes zwischen den Releases ändern oder einfach eine Funktion entfernen, was Babel tut. Für manche (Unternehmen?) Projekte ist das wichtig.

Ich kann auch verstehen, dass MS nicht viele Ressourcen in Funktionen investieren möchte, die möglicherweise wegfallen, da fällt mir das Object.observe Fiasko ein. Tatsächlich sagten sie, sie würden eine PR für dieses Thema in Betracht ziehen, zum Beispiel: zwinker:.

In der Vergangenheit wurden einige Funktionen früh hinter einem experimentellen Compiler-Schalter (zB async) hinzugefügt, was bedeutete, dass Sie sich anmelden und akzeptieren mussten, dass sich die Funktion in zukünftigen Versionen ändern oder entfernt werden könnte. Vielleicht könnte man das für die beliebtesten Anfragen wiederholen?

Hier nur eine kurze Anmerkung. Wir haben die vorgeschlagenen ES-Funktionen der Stufe 0-1 eher langsam übernommen, hauptsächlich aufgrund von Bedenken hinsichtlich der Abwärtskompatibilität. Wir verfolgen die Diskussionen in den TC39-Meetings aufmerksam und nehmen direkt an den Meetings oder an der Vorschlagsvorbereitung vor den Meetings teil; und wenn wir eine Funktion einbauen, möchten wir wissen, was das für Benutzer bedeutet, die von ihnen abhängig sind.
Wenn Sie sich die TC39-Prozessdokumentation ansehen, kann ein Feature in Stufe 1 mit "großen" Änderungen nach der Abnahme rechnen. Dies war bei Klassen, Modulen, Iteratoren und fast allen nicht trivialen ES6-Funktionen der Fall.
Wenn ich meinen Benutzerhut aufsetze, kann es sein, dass Änderungen an der Syntax mechanisch zu reagieren sind, während es extrem schwierig sein kann, Änderungen an der Semantik zu erkennen und zu beheben. Dies kann für Teams, die eine dieser Funktionen verwenden, enorme Kosten verursachen und/oder ein Blocker für die Einführung neuerer Versionen der Tools sein. und das möchten wir nach Möglichkeit minimieren. Aus diesem Grund haben wir eine Richtlinie verabschiedet, um Funktionen standardmäßig zu aktivieren, wenn sie Stufe 3 erreichen, und davor unter einer experimentellen Flagge (z. B. Dekorateure).
Allerdings stehen die Objekteigenschaft Spread and Rest auf unserer Roadmap , und wir planen, sie in einer zukünftigen Version anzugehen.

Vielleicht ist es eine Überlegung wert, dem Compiler die Fähigkeit hinzuzufügen, einige Erweiterungen von Drittanbietern einzufügen, wie dies in babel der Fall ist?

Ein weiterer Gedanke: Wie sieht es mit der Unterstützung für die Vorverarbeitung von Typoskriptquellen (mit Babel) aus?

Wenn wir Babel (oder eine andere Bibliothek) dazu bringen können, Objektverbreitungen in Object.assign Aufrufe zu erweitern, könnte das gut genug funktionieren? Es wäre hoffentlich auch auf andere experimentelle Funktionen übertragbar, die in Babel implementiert sind.

@kitsonk - breiteres Thema unbedingt, wünschte, github hätte bessere Diskussionen ;). Ich stimme Ihnen ziemlich nicht zu:

. TypeScript wurde schon zuvor massiv gebissen, indem es mit der Waffe gesprungen ist (Module, und schauen Sie sich das Chaos an, das seitdem verursacht hat).

Sie gingen los und machten ihre eigene Implementierung, die .NET spiegelte, ohne etwas aus der Community zu verwenden, das ist ihre eigene Schuld.

Legen Sie eine Anleitung und Struktur fest, was sie wann implementieren möchten

Sie implementieren Dekoratoren (Stufe 1), Klasseneigenschaften (Stufe 1) usw.

Ich glaube nicht, dass "weil das X-Framework es in seinen Dokumenten erwähnt" gut wäre.

du machst nur Spaß, oder? Reagieren ist das beliebteste Framework und wird voraussichtlich noch eine Weile so bleiben. das nicht zu unterstützen, wird/hat der Annahme wirklich geschadet.

Ich denke, TypeScript hat mit Babel viel Nachholbedarf und es gibt viele Herausforderungen wie: wirklich schwierig, es mit einer bestehenden App zu verwenden, die Migration von Babel zu Typescript für A2 ist ein Albtraum!, Fehlen entkoppelter Plugins macht das Arbeiten mit Node extrem schwierig.

du machst nur Spaß, oder? Reagieren ist das beliebteste Framework und wird voraussichtlich noch eine Weile so bleiben. das nicht zu unterstützen, wird/hat der Annahme wirklich geschadet.

Ich habe großen Respekt vor React, aber ich mache keine Witze. Es ist nicht das einzige Spiel in der Stadt und es befindet sich sicherlich auf einer großen Hype-Kurve. Vor 6 Monaten war es React + Flux, jetzt ist React + Redux der Geschmack des Tages. Vor einem Jahr Angular und Polymer. Vor zwei Jahren war es Backbone and Ember. Vor sechs Jahren waren es Dojo, MooTools, jQuery, gwt, ExtJS, etc...

fang hier keine Frameworkkriege an :exclamation:
{..., } Syntax ist so wie sie ist sehr schön, egal welches Framewrok

Sie gingen los und machten ihre eigene Implementierung, die .NET spiegelte, ohne etwas aus der Community zu verwenden, das ist ihre eigene Schuld.

@amcdnl Was genau

+1 für die Aufnahme in den Typoskript-Knoten js unterstützt dies exprimiert

let typescript = { ...typescript, object_spread }; // Ja bitte.

Schade, es gibt keine Bewegung, ich hoffe wirklich, dass dies bald Stufe 3 erreicht. Wenn möglich, wird die Hervorhebung von Syntaxfehlern in VSCode beendet

Ich frage mich, ob Salsa etwas am Spiel ändert?

Ich verstehe, dass TS keine instabilen Funktionen frühzeitig implementieren möchte: begrenzte Ressourcen, Abschirmung von uns Benutzern vor möglichen Breaking Changes usw.

Aber jetzt, da Salsa die Standard-JS-Engine von VS Code ist, wird der Druck auf eine neuere JS-Syntax (zumindest nur die Syntax, nicht die vollständige TS-Typisierung) zunehmen. Vor allem angesichts der Popularität von Babel.

Wird Salsa eine breitere Syntax schneller akzeptieren können als TS?

+1

Wird das in 2.1 statt 2.0 sein? :schreien:
https://github.com/Microsoft/TypeScript/wiki/Roadmap#21

Wenn man bedenkt, wie groß 2.0 schon jetzt ist, überrascht mich das nicht.

Wir versuchen, die Releases im Abstand von 6-8 Wochen zu halten; Das schränkt die Möglichkeiten ein. Wir führen derzeit einige Emitter-Refactoring durch und sollten in der Lage sein, diese Funktion hinzuzufügen, sobald dies abgeschlossen ist.

Ist das also behoben?

...eigenständige Hilfsfunktion für Spread-Attribute
https://github.com/Microsoft/TypeScript/releases/tag/v1.8.10

Da ich immer noch "Property Restrukturierungsmuster erwartet" bekomme

Nicht genau. Dieser Fix gilt speziell für JSX-Spread-Attribute:

const props = { foo: "bar" };
return <SomeComponent {...props} />;

was bereits funktionierte, bevor React v15 eine undokumentierte interne Funktion entfernte, von der der JSX-Compiler von TypeScript abhängig war. Ups

Die Objektverteilung ist ein anderer Vorschlag mit einer zugegebenermaßen ähnlichen Syntax (möglicherweise wurde sie sogar von Facebook-Ingenieuren vorgeschlagen und vom JSX-Äquivalent inspiriert, obwohl ich es nicht genau weiß).

Da {...props} noch nicht funktioniert, wie würden Sie mit TypeScript etwas Ähnliches erreichen?

Da {...props} noch nicht funktioniert, wie würden Sie mit TypeScript etwas Ähnliches erreichen?

Verwenden Sie xtend : https://www.npmjs.com/package/xtend es hat großartige Eingaben: https://github.com/typed-typings/npm-xtend (von @blakeembrey :rose:) danke zum Kreuzungstyp

Oder benutzen Sie gar keine Bibliothek!

const newProps = Object.assign({} /*new object*/, props /* add all attributes of props */, {
   // add additional props
  bar: "baz"
});

Es ist ein bisschen ausführlich, aber es _ist_ nativ in ES2015. Wenn Sie also bereits einen Polyfill dafür haben, sind Sie solide.

Dieser Operator ist einer der Hauptgründe, warum wir uns entschieden haben, in einem Projekt Babel anstelle von Typoskript zu verwenden.

Ändert das Spiel für den unveränderlichen Umgang mit Objekten vollständig.

Ist als Alternative etwas geplant, mit dem Sie eine benutzerdefinierte Transformation in TSC einbinden können, wie Sie es in Babel tun können? Vielleicht sogar basierend auf derselben API, das wäre großartig und würde solche Probleme lösen.

Als Alternative ist etwas geplant, das es Ihnen ermöglicht, eine benutzerdefinierte Transformation in TSC einzubinden, wie Sie es in Babel tun können

@Niondir Ja. Suchen Sie einfach nach den Tags [Transforms] . Diese werden benötigt, um eine ordnungsgemäße async/await/generator-transpilation in den TypeScript-Compiler zu erhalten :rose:

Nach einer kleinen Suche verweisen Sie darauf? https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API

Klingt großartig. Ich finde einfach nichts, was mit der Objektverteilung für diese API zu tun hat. Vielleicht wäre es ein nettes kleines Projekt, um dieses Problem basierend auf der Compiler-API zu lösen :)

@Niondir Entschuldigung, dass ich in meiner ursprünglichen Nachricht keine bessere Hilfe bereitgestellt habe. Ich spreche von https://github.com/Microsoft/TypeScript/issues/5595 < was ein steckbares emit für die ESNext-Syntax ermöglicht. TypeScript ist etwas komplizierter als Babel, weil es ein _semantisches_ Systemverständnis Ihres Codes haben muss, sodass die Arbeit zur Objektverteilung wahrscheinlich vom TypeScript-Team kommen muss.

Ein Plugin-basierter Emitter würde dies einfacher machen. Ja, Sie würden die Compiler-API verwenden (oder möglicherweise fork den Compiler am Anfang, bis ein Plugin-System veröffentlicht wird + für die Semantik / Scanner-Logik)

Dies könnte eine Frage für ein anderes Problem sein, aber wäre es nicht möglich, eine Option "allow-experimental" hinzuzufügen und TypeScript zukünftige Dinge zuzulassen? Lassen Sie beispielsweise den Spread-Operator und die Ausgabe unverändert zu. Das kann ich mit Babel hinterher vertragen.

Dies ist ein Muss für einige Projekte, an denen ich arbeite, und ich kann ohne solche wichtigen Dinge nicht migrieren. Es wäre toll, wenn ich könnte.

Ich bin mir nicht sicher, wie wir es letztendlich versenden werden, aber ich habe mit der Arbeit an Rest/Spread in Objektliteralen und Destrukturierung begonnen . Im Moment ist der Plan, unser Polyfill __assign Emittieren zu verwenden.

Das ist die beste Nachricht, die ich in den letzten 3 Monaten gehört habe!

Leider stellt sich heraus, dass es eine Menge Arbeit ist, dies mit Generika zum Laufen zu bringen. Sie müssen Code wie diesen richtig unterstützen:

function addId<T>(t: T): {...T, id: number} {
    return { ...t, id: 1 };
}

Wie Sie sehen, gibt addId einen neuen Typ zurück, einen Objekttyp, der einen Spread-Operator enthält.

Nach einigen Diskussionen haben wir uns entschieden, bis 2.1 zu verschieben und uns dies noch einmal anzusehen. Wir müssen uns jetzt darauf konzentrieren, die 2.0-Funktionen fertigzustellen.

Verzeihen Sie meine Unwissenheit ... aber es fühlt sich an, als ob addId in diesem Fall T & { id: number } ? Oder gibt es eine Eigenart der Gewerkschaftstypen, die dies davon abhält, eine optimale Lösung zu sein?

Ich denke, er meint, dass eigentlich T angekreuzt werden sollte, da man alles an T weitergeben kann

addId<boolean>(true);
addId<number>(5);

Babel ignoriert solche Aussagen stumm let a = { ...true } aber ich denke, sie sollten nicht gültig sein

Es ist nicht T & { id: number } denn wenn T eine id Eigenschaft hat, wird diese überschrieben.

Auf der anderen Seite, die Kreuzung, die sich ergebende Art von id wäre der Durchschnitt von T ‚s id Art und number .

Was @sandersn sagt, ist, dass Sie einen separaten

Während wir hier definitiv von einer besseren Typisierungslösung profitieren würden, gibt es Object.assign bereits und verwenden Schnittmengen naiv als Ausgabetyp. Warum konnten wir nicht als Stop-Gap-Maß den Restoperator genau das tun lassen, was Object.assign tut?

Es würde viele Bedenken hinsichtlich der fehlenden Funktion ausräumen und würde kein unerwünschtes Verhalten mit sich bringen, da die Leute stattdessen bereits Object.assign verwenden.

War wirklich sehr überrascht, dass dies nicht unterstützt wurde.

Sobald wir das bekommen, desto besser. Funktioniert super mit Reagieren!

Ich würde mich freuen, auch wenn es nicht getippt wäre

@ 2426021684 Es mag vernünftig klingen, aber bedenken Sie die Auswirkungen. Wenn es nicht typisiert ist, d. h. als any typisiert ist, wird jede Verwendung der Syntax any zu den Blättern von Ausdrücken durchsickern lassen.

@aluanhaddad es wäre dasselbe wie Object.assign was die Problemumgehung ist, die jeder verwenden muss, weil sie keine Wahl haben (siehe JabX-Post oben).

Bitte ziehen Sie in Erwägung, den Vorschlag von @JabX in naher Object.assign wäre eine sehr hilfreiche Notlösung, während wir auf die "richtige" Implementierung warten. Lass das Perfekte nicht der Feind des Guten sein.

Ruheeigenschaften sind bei React 15.2 extrem wichtig, wie hier https://facebook.github.io/react/warnings/unknown-prop.html zu sehen ist

const divProps = Object.assign({}, props)
delete divProps.layout

ist sehr hässlich, besonders wenn die Anzahl der Requisiten an einem Bauteil höher ist

Für diejenigen, die nicht mehr warten können, hier eine Problemumgehung:

function steal(result: any, data: any): any {
    for (var key in data) {
        if (value.hasOwnProperty(key)) {
            result[key] = data[key];
        }
    }
    return result;
}

export class SameAs<a> {
    constructor(public result: a) { }
    public and<b>(value: b): SameAs<a & b> {
        return new SameAs<a & b>(steal(this.result, value));
    }
}
export function sameAs<a>(value: a): SameAs<a> {
    return new SameAs(steal({}, value));
}

// example of use:

const mixture = sameAs(one).and(anotherOne).and(yetAnotherOne).result; // <-- ta-da!

Ignoriere diesen Beitrag, siehe unten für eine bessere Implementierung

Hier ist, was ich mir für die Destrukturierungsoperation eines schlechten (Typoskript-)Codierers ausgedacht habe:

declare interface ObjectConstructor {
  destruct<T extends Object>(data: T, props: any): T;
  destruct<T extends Object>(data: T, ...propNames: string[]): T;
}

function destruct<T extends Object>(data: T, ...removals: string[]) {
  const rest = <T>{};

  const keys = removals.length === 1 && typeof removals[0] === 'object' ?
    Object.getOwnPropertyNames(removals[0]) :
    <string[]>removals;

  Object
    .getOwnPropertyNames(data)
    .filter(x => keys.indexOf(x) < 0)
    .forEach(x => {
      (<any>rest)[x] = (<any>data)[x];
    });

  return rest;
}

Object.destruct = destruct;

// Usage example:

const srcObj = { A: 'a', B: 'b', C: 'c' };
// destruct using an object template
const onlyC = Object.destruct(srcObj, { A: null, B: null });
// destruct using property names
const onlyA = Object.destruct(srcObj, 'B', 'C');

Der offensichtliche Vorteil der Verwendung eines Objektlayouts besteht darin, dass Sie das Layout eingeben können und zumindest Typkonflikte auftreten, wenn Sie etwas umgestalten.

Update (auch dies ignorieren, siehe unten für noch besseres)

Ich habe dies überarbeitet (nachdem ich in einer realen Umgebung damit herumgespielt habe) und bin auf einige viel einfachere Funktionen gekommen.

function deconstruct<TResult, TData>(
  result: TResult,
  data: TData,
  onHit: (result: TResult, data: TData, x: string) => void,
  onMiss: (result: TResult, data: TData, x: string) => void,
  propNames: string[]
  ) {

  Object
    .getOwnPropertyNames(data)
    .forEach(x => {
      if (propNames.indexOf(x) < 0) {
        if (onMiss != null) {
          onMiss(result, data, x);
        }
      }
      else {
        if (onHit != null) {
          onHit(result, data, x);
        }
      }
    });

  return result;
}

// shallow clone data and create a destructuring array of objects
// i.e., const [ myProps, rest] = destruct(obj, 'propA', 'propB');
function destruct<T>(data: T, ...propNames: string[]) {
  return deconstruct(
    [ <T>{}, <T>{} ],
    data,
    (r, d, x) => (<any>r[0])[x] = (<any>d)[x],
    (r, d, x) => (<any>r[1])[x] = (<any>d)[x],
    propNames
  );
}

// shallow clone data and create a destructuring array of properties
// i.e., const [ propA, propB, rest] = destructProps(obj, 'propA', 'propB');
function destructProps(data: any, ...propNames: string[]) {
  return deconstruct(
    [ <any>{} ],
    data,
    (r, d, x) => r.splice(r.length - 1, 0, d[x]),
    (r, d, x) => r[r.length - 1][x] = d[x],
    propNames
  );
}

// shallow clone data and remove provided props
// i.e., const excluded = omit(obj, 'excludeA', 'excludeB');
function omit<T>(data: T, ...propNames: string[]) {
  return deconstruct(
    <T>{},
    data,
    null,
    (r, d, x) => (<any>r)[x] = (<any>d)[x],
    propNames
  );
}

Das Tippen auf diese Funktionen macht die Arbeit viel einfacher. Ich arbeite speziell mit diesen in React, daher ist es sehr praktisch, bei meinen bekannten Requisiten starkes Tippen zu haben. Es gibt einen zusätzlichen Code, der diese Funktionen verwendet, der besonders praktisch für Reagieren ist:

const [ props, restProps ] = destruct(omit(this.props, 'key', 'ref'), 'id', 'text');

In diesem Fall wird props wie this.props eingegeben, enthält jedoch keine der Requisiten, die für die Übertragung in der Zeile gedacht sind (die jetzt in restProps ).

IMO, es wird nicht viel gewonnen, wenn nicht typsichere Problemumgehungen für dieses Problem veröffentlicht werden.

zugestimmt, ich arbeite gerade an einer typsichereren Version.

Noch ein Stich dazu:

Die Hauptobjekterweiterung:

declare interface ObjectConstructor {
    rest<TData, TProps>(data: TData, propsCreator: (x: TData) => TProps, ...omits: string[]): { rest: TData, props: TProps };
}

function rest<TData, TProps>(data: TData, propsCreator: (x: TData) => TProps, ...omits: string[]) {
  const rest = <TData>{};
  const props = <TProps>propsCreator.apply(this, [ data ]);

  Object
    .getOwnPropertyNames(data)
    .filter(x => props.hasOwnProperty(x) === false && omits.indexOf(x) < 0)
    .forEach(x => {
      (<any>rest)[x] = (<any>data)[x];
    });

  return {
    rest,
    props,
  };
}

Object.rest = rest;

Eine React-spezifische Erweiterung:

declare module React {
  interface Component<P, S> {
    restProps<T>(propsCreator: (x: P) => T, ...omits: string[]): { rest: P, props: T };
  }
}

function restProps<P, S, T>(propsCreator: (x: P) => T, ...omits: string[]) {
  return Object.rest((<React.Component<P, S>>this).props, propsCreator, ...omits.concat('key', 'ref'));
}

React.Component.prototype.restProps = restProps;

Einige Beispielverwendungen:

const src = { A: 'a', B: 'b', C: 'c' };
const { rest, props } = Object.rest(src, x => {
    const props = { A, C } = x;
  return { A, C };
});

Und ein Beispiel für die Verwendung der React-Erweiterung:

const { rest, props } = this.restProps(x => {
  const { header, footer } = x;
  return { header, footer };
});

Alle Eingaben sollten erhalten bleiben. Der einzige Teil, der mich stört, ist der Requisiten-Ersteller, da er dupliziert werden muss. Ich denke, ich könnte es hacken und annehmen, dass das destrukturierte Objekt bei _a lebt, aber das scheint _gefährlich_ zu sein ...
_HINWEIS _: _a ist nicht einmal ein brauchbarer Hack, da es x .

Hier ist eine Geige zum Herumspielen.

Ich denke, die Rückgabe eines Arrays könnte sinnvoller sein, da Sie die Ausgaben nach Bedarf umbenennen können.

kratzen Sie daran, dies würde verhindern, dass die Requisiten richtig eingegeben werden.

Da die meisten Leute hier dies mit Reagieren verwenden möchten, warum implementieren Sie dies nicht nur für *.tsx-Dateien, bis es Stufe 3 erreicht?

Redux Reducer können auch als *.tsx-Dateien geschrieben werden, nurobj Typcasting-Instanzen sollten als Typ in obj konvertiert werden

Dies ist nicht nur für React sehr nützlich, sondern zum Beispiel für Redux Reducer.

Ich denke, die Tags und der fehlende Meilenstein sind etwas veraltet. Weil dies für TypeScript 2.1 festgeschrieben ist und daran gearbeitet wird (#10727). Über den Wert muss also nicht mehr diskutiert werden.

ping @mhegazy

Die Tags aktualisiert. Ich sollte klarstellen, dass der Grund dafür, dass dies noch nicht implementiert wurde, nicht der Wert, sondern die Komplexität der Typsystemimplementierung ist. die Transformation selbst ist eher trivial, dh {...x} in Object.assign({}, x) . Das Problem ist, wie diese Typen vorab getestet werden und wie sie sich verhalten. zum Beispiel für einen generischen Typparameter T ist {...T} zuweisbar T , was ist mit {x: number, ...T} , was ist, wenn T Methoden hat, etc.. https://github.com/Microsoft/TypeScript/issues/10727 bietet eine ausführlichere Erläuterung der erforderlichen Typsystemänderungen.

Ich weiß voll und ganz zu schätzen, dass die für eine optimale Behandlung dieser Funktion erforderlichen Schriftsystemerweiterungen nicht trivial sind, und es ist großartig zu sehen, dass sie mit Begeisterung in Angriff genommen werden! Ich möchte das nur wiederholen,

Die syntaktische Unterstützung für Property Spreads + naive Typisierung von Object.assign wäre eine sehr hilfreiche Notlösung, während wir auf die "richtige" Implementierung warten. Lass das Perfekte nicht der Feind des Guten sein.

Es scheint, als hätte der Vorschlag Stufe 3 erreicht: https://github.com/tc39/proposals

@ddaghan dein Beispiel mit tsx wird nicht funktionieren

Gibt es einen Zeitrahmen für diese Funktion?

@SpyMaster356 Ich habe das schon eine Weile @sandersn hat sich (zumindest) in den letzten Wochen damit beschäftigt. 🙌.

Sie können hier (https://github.com/Microsoft/TypeScript/pull/12028) und hier (https://github.com/Microsoft/TypeScript/pull/11150) folgen.

Jemand sollte die Roadmap aktualisieren

Es scheint, dass die Verwendung dieser Funktion die Zuweisung unbekannter Requisiten ermöglicht:

interface State {
  a: string;
  b: number;
}

let state: State = { a: "a", b: 0 };

state = {...state, x: "x"}; // No error

Ich habe einen Fehler erwartet, dass x keine bekannte Eigenschaft von State . Funktioniert die Funktion nicht so?

Meine aktuelle Problemumgehung vor dieser PR war zum Beispiel:

state = update(state, { x: "x" }); // Error: Property 'x' is missing in type 'State'.

function update<S extends C, C>(state: S, changes: C): S {
  return Object.assign({}, state, changes);
}

Ist dies mit Object Spread/Rest möglich?

Object Rest and Spread verhält sich gemäß dem ES-Vorschlag ähnlich wie Object.assign . die letzte Erwähnung der Immobilie "gewinnt". es werden keine Fehler gemeldet. In dem Beispiel, das Sie hatten, ist der Typ von {...state, x:"X"} { a: string, b:number, x:string } ; und dieser Typ ist State zuweisbar und somit funktioniert die Zuweisung. Das ist dasselbe, als würde man sagen, dass let state: State = { a: "a", b:0, x: "X" }; auch erlaubt wäre.

Aber das ist es, was mich verwirrt: let state: State = { a: "a", b:0, x: "X" } gibt den Fehler Object literal may only specify known properties, and 'x' does not exist in type 'State' , was ich will ... warum ist es eine gültige Zuweisung, wenn sie aus einem Objektliteral mit Spreads kommt?

sorry.. Objektliterale sind ein Sonderfall. mein Beispiel war falsch. hier ist ein besseres beispiel:

let obj = { a: "a", b:0, x: "X" };
let state: State = obj; // OK

Das Problem hier ist, wenn auch eher subjektiv. Wenn der Compiler let state:State = { a: "a", b:0, x: "X" } sieht, besteht die Möglichkeit, dass x ein Tippfehler ist, entweder eine veraltete Eigenschaft, die nach dem Refactoring weggelassen wurde, oder ein Typ für eine optionale Eigenschaft, deshalb wird dies als an . gemeldet Error.

Wenn Sie jedoch ein Objekt verteilen, sagen wir let myConfig : State= { a: 1, ...myOtherBigConfigBag} , wenn myOtherBigConfigBag einige Eigenschaften hat, die Ihnen egal sind, brauchen Sie nur die a und die b , ein Fehler hier würde Sie dazu zwingen, diese beiden Schnittstellen synchron zu halten oder umzuwandeln, um diese Fehler zu beseitigen.

das gesagt. Wir sollten diese Entscheidung noch einmal überdenken. https://github.com/Microsoft/TypeScript/issues/12717 eingereicht, um dies zu verfolgen.

Ich verstehe. Ich liebe deine Idee in #12717, genau das habe ich auch gedacht. Ich würde ein solches Verhalten sogar für die Spread-Requisiten wünschen, aber ich kann Ihren Standpunkt verstehen, dass es sehr subjektiv ist und für einige gängige JS-Anwendungsfälle ärgerlich sein könnte.

@aaronbeall Ich stimme zu, es wäre ärgerlich für gängige JS-Anwendungsfälle ... Meistens möchten Sie nur sicherstellen, dass das Objekt die Form der angegebenen Schnittstelle hat und das verteilte Objekt nicht direkt inspizieren, die aktuelle Implementierung ist IMO in Ordnung

Hallo Leute, Glückwunsch zur tollen Veröffentlichung! Jetzt ist es Zeit für eine verdiente Pause ... ich habe ein Problem mit dem Rest-Operator :)

Mit React haben Sie typischerweise eine Komponente wie:

export interface MyLinkProps extends React.HTMLAttributes {
    myUrl: string
}

class MyLink{

    render(){
      const {myUrl, ...attrs } = this.props;
     return <a href={calculate(myUrl)} ...attrs>Click here</a>;
   }
}

Das Problem ist, dass, wenn Sie mit der Maus über attrs Sie die Liste aller Eigenschaften (Hunderte) anstelle von React.HtmlAttributes erhalten.

Ich weiß, dass Typoskript strukturell typisiert ist und all das, aber könnte es möglich sein, der Restvariablen einen expliziten Typ zuzuweisen?

Einige Alternativen:

    const {myUrl, ...attrs as React.HtmlAttributes } = this.props; //Is not really a casting

    const {myUrl, ...attrs : React.HtmlAttributes } = this.props; //conflicts with ES6?

    const attrs : React.HTMLAttributes; 
    const { myUrl, ...attrs } = this.props;  //re-declare the variable

@bondz Nun, das stimmt nicht in 100% der Verwendungen in meinem Projekt. :) Aber in einem anderen Projekt kann es sehr nervig sein. In meinem Fall verwende ich Redux und React und nutze stark den unveränderlichen Zustand, was bedeutet, dass ich zum Aktualisieren oder Erstellen von Zustandsobjekten alle Requisiten auf ein neues Objektliteral kopieren muss ... in allen Fällen möchte ich 100%ige Typsicherheit, die ich Ich versuche, die richtigen Daten auf die Zielzustandsschnittstelle zu kopieren. Derzeit verwende ich Funktionen, um diese Sicherheit zu gewährleisten, aber ich würde es vorziehen, die Objektverteilung zu verwenden, da sie sauberer ist (lesbar, ausdrucksstark, Standardsyntax). Aber in einem Projekt anderer Personen möchten sie möglicherweise ein anderes Verhalten, da sie viele nicht typisierte oder lose Objekte verwenden Strukturen, also sehe ich, wie es ziemlich subjektiv ist. Ich denke, der Vorschlag Nr. 12717 ist ein guter Mittelweg (und konsistenter mit der bestehenden Sicherheit des Objektliterals).

https://github.com/Microsoft/TypeScript/issues/2103#issuecomment -145688774
Wir wollen warten, bis der Vorschlag Stufe 3 erreicht, bevor wir uns damit befassen.

Anscheinend ist es bereits Zustand 3, gibt es einen Plan, dies zu unterstützen?

Übrigens, wir verwenden VSCode hauptsächlich für die ES-Entwicklung, noch nicht für TS :)

@evisong Diese Funktion wurde ausgeliefert und ist bereits in der neuesten Version von vsCode verfügbar. Aktualisieren Sie Ihren vsCode auf Version 1.8

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen