Typescript: Unterstützung des vorgeschlagenen ES Next-Pipeline-Betreibers "|>"

Erstellt am 10. Aug. 2017  ·  79Kommentare  ·  Quelle: microsoft/TypeScript

ES Next Suggestion Waiting for TC39

Hilfreichster Kommentar

Es ist jetzt in Stufe 1

Alle 79 Kommentare

Mein Lieblingsvorschlag überhaupt :( Heutzutage können wir wirklich this kostenlose Programme schreiben.

Als Referenz der TC39-Vorschlag: https://github.com/tc39/proposal-pipeline-operator

Nicht, dass der Vorschlag noch nicht einmal in Stufe 0 ist. Wenn es jemals zur Sprachsemantik hinzugefügt wird, werden sich wahrscheinlich andere Details ändern.

Dies wäre meiner Meinung nach das erste Mal (neben einigen Oldies wie Enum und dem Modulsystem), aber könnte die Implementierung durch Typoskript mehr Sichtbarkeit verleihen und die Nachfrage im Rest des Ecma-Ökosystems steigern?

Wollte nur eine Problemumgehung für den fehlenden Pipeline-Operator teilen, inspiriert von

SyncPipe mit synchroner Reduzierung

// SyncPipe with synchronous reduction
type SyncPipeMapper<T, U> = (data: T | U) => U;
type SyncPipeReducer<T, U> = (f: SyncPipeMapper<T, U>, g: SyncPipeMapper<T, U>) => SyncPipeMapper<T, U>;
type SyncPipe<T, U> = (...fns: SyncPipeMapper<T, U>[]) => SyncPipeMapper<T, U>;
function createSyncPipe<T, U>(): SyncPipe<T, U> {
    const syncPipe: SyncPipeReducer<T, U> = (f: SyncPipeMapper<T, U>, g: SyncPipeMapper<T, U>) => (data: T) => g(f(data));
    return (...fns: SyncPipeMapper<T, U>[]): SyncPipeMapper<T, U> => fns.reduce(syncPipe);
}

// Example:
function testSyncPipe(num: number): number {
    const addOne: SyncPipeMapper<number, number> = (data: number): number => {
        return data + 1;
    }
    const syncPipe: SyncPipe<number, number> = createSyncPipe();
    const syncWaterfall: SyncPipeMapper<number, number> = syncPipe(
        addOne,
        addOne,
        addOne,
    );

    // Does the equivalent of num+3
    const lastnumber: number = syncWaterfall(num);
    return lastnumber;
}

AsyncPipe mit asynchroner Reduktion

// AsyncPipe with asynchronous reduction
type AsyncPipeMapper<T, U> = (data: T | U) => Promise<U>;
type AsyncPipeReducer<T, U> = (f: AsyncPipeMapper<T, U>, g: AsyncPipeMapper<T, U>) => AsyncPipeMapper<T, U>;
type AsyncPipe<T, U> = (...fns: AsyncPipeMapper<T, U>[]) => AsyncPipeMapper<T, U>;
function createAsyncPipe<T, U>(): AsyncPipe<T, U> {
    const asyncPipe: AsyncPipeReducer<T, U> = (f: AsyncPipeMapper<T, U>, g: AsyncPipeMapper<T, U>) => async (data: T) => g(await f(data));
    return (...fns: AsyncPipeMapper<T, U>[]): AsyncPipeMapper<T, U> => fns.reduce(asyncPipe);
}

// Example:
async function testAsyncPipe(num: number): Promise<number> {
    const addOne: AsyncPipeMapper<number, number> = async (data: number): Promise<number> => {
        return data + 1;
    }
    const asyncPipe: AsyncPipe<number, number> = createAsyncPipe();
    const asyncWaterfall: AsyncPipeMapper<number, number> = asyncPipe(
        addOne,
        addOne,
        addOne,
    );

    // Does the equivalent of num+3
    const lastnumber: number = await asyncWaterfall(num);
    return lastnumber;
}

Rohr mit asynchroner Reduzierung (vereinfacht)

Ich benutze dieses die meiste Zeit:

// Pipes with asynchronous reduction
type PipeMapper<T> = (data: T) => Promise<T>;
type PipeReducer<T> = (f: PipeMapper<T>, g: PipeMapper<T>) => PipeMapper<T>;
type Pipe<T> = (...fns: PipeMapper<T>[]) => PipeMapper<T>;
function createPipe<T>(): Pipe<T> {
    const pipePipe: PipeReducer<T> = (f: PipeMapper<T>, g: PipeMapper<T>) => async (data: T) => g(await f(data));
    return (...fns: PipeMapper<T>[]): PipeMapper<T> => fns.reduce(pipePipe);
}

// Example:
async function testPipe(num: number): Promise<number> {
    const addOne: PipeMapper<number> = async (data: number): Promise<number> => {
        return data + 1;
    }
    const pipe: Pipe<number> = createPipe();
    const waterfall: PipeMapper<number> = pipe(
        addOne,
        addOne,
        addOne,
    );
    // Does the equivalent of num+3
    const lastnumber: number = await waterfall(num);
    return lastnumber;
}

Ich hoffe, Sie finden das hilfreich!

@PublicParadise viel zu viel Boilerplate :p

Obwohl ich definitiv gerne eine Variante dieses Operators in der Sprache sehen würde, ergibt sich die wahrgenommene Notwendigkeit dafür aus zwei verschiedenen Einschränkungen von ECMAScript in seiner derzeitigen Form.

Das erste ist sehr schwer zu umgehen oder gar in der Sprache anzusprechen: die Unfähigkeit, eingebaute Objekte hygienisch zu erweitern.

Die zweite benötigt jedoch überhaupt keine Unterstützung auf Sprachniveau und könnte tatsächlich behoben werden: Die Standardbibliothek kann freundlicherweise als anämisch bezeichnet werden.

Maximal Minimal ist ein kompletter Fehler.

Warum dauert es Monate und Monate der Auseinandersetzung, um Array.prototype.flatMap in der Sprache zu bekommen?

Das ist eine Methode und sie sollte von Anfang an vorhanden sein und es sollte offensichtlich sein, dass sie hinzugefügt werden sollte.

Vielleicht wird Array.prototype in 6 Jahren eine groupBy Methode haben.

Inzwischen gibt es einige Babel-Implementierungen, die hoffentlich beim TC39-Vorschlag helfen werden:

Es ist jetzt in Stufe 1

Also, irgendwelche Chancen, dass diese Schönheit zu TS kommt? Es würde mit F# übereinstimmen. <3

Es gibt zwar Ausnahmen, aber wenn ein Vorschlag für TypeScript und Typen _wichtig_ ist, werden Vorschläge in der Regel erst implementiert, wenn sie TC39 Stufe 3 in TypeScript erreichen, da sie nicht stabil genug sind, um sicherzustellen, dass es keine signifikanten Brüche und Regressionen gibt.

Obwohl sich noch keiner aus dem Kernteam zu diesem Thema geäußert hat, wäre es meiner Meinung nach nicht _wichtig_ genug, um vor Phase 3 für die Implementierung in Betracht gezogen zu werden. Der beste Fokus liegt darauf, den Champion und den Vorschlag bei TC39 zu unterstützen.

Wenn TS nur die Möglichkeit hätte, diesen Operator einfach durchzuleiten, damit ein Babel mit Plugins damit umgehen kann.
Oder hatte eigene Syntax-Plugins, wie es post-css tut. Mehrere Jahre warten auf einen primitiven Operator ist einfach zu viel.

@garkin : Die Herausforderung hier besteht darin, dass TS den Code verstehen muss, um seine Aufgabe der Bereitstellung von Typsicherheit zu erfüllen, die sich nicht gut mit zufälligem Code kombinieren lässt, den er nicht versteht. Es sei denn, es würden Makros (#4892) abgerufen, in diesem Fall würde es nur in Code kompiliert, den es versteht. Aber das würde ich auf der Roadmap noch nicht erwarten, da einige Teile der Standardbibliothek noch schwer zu tippen sind.

Da Babel nun Typoskript versteht, könntest du es dann durch Babel laufen lassen
Typoskript

Am 26. Oktober 2017, 19:01 Uhr, schrieb "Tycho Grouwstra" [email protected] :

@garkin https://github.com/garkin : Die Herausforderung hier ist, dass TS muss
den Code verstehen, um seine Aufgabe der Bereitstellung von Typsicherheit zu erfüllen, was nicht der Fall ist
gut mit zufälligem Code kombinieren, den es nicht versteht. Es sei denn, es wäre zu bekommen
Makros (#4892 https://github.com/Microsoft/TypeScript/issues/4892 ), in
In diesem Fall würde es nur zu Code kompiliert, den es versteht. Aber ich würde nicht
erwarte das noch auf der Roadmap, da einige Teile des Standards
Bibliothek sind immer noch schwierig zu tippen atm.


Sie erhalten dies, weil Sie den Thread verfasst haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339748284 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAZQTO6UiVHbrM6SRwaBhm8obaa3R7e9ks5swMkCgaJpZM4OzVEg
.

Da Babel nun Typoskript versteht, könntest du es dann durch Babel laufen lassen
Typoskript

Doppelte Bauzeit :p

Wäre schön, wenn Typescript nur ein Babel-Plugin wäre, dann müsstest du es nicht
Pipe durch beide Programme

Am 26. Oktober 2017 um 20:16 Uhr schrieb "AlexGalays" [email protected] :

Da Babel nun Typoskript versteht, könntest du es dann durch Babel laufen lassen
Typoskript

Doppelte Bauzeit :p


Sie erhalten dies, weil Sie den Thread verfasst haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339769856 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAZQTEArBw8jj0BcZFM2yLj5ErfbtNrgks5swNqagaJpZM4OzVEg
.

@graingert : Es ist eine schöne Option, ich werde das untersuchen.
Leider funktioniert es nicht mit der Typescript Language Service API, die von VisualStudioCode, Webstorm und anderen IDEs verwendet wird.

In Bezug auf "TS-Plugins" könnte man leicht das gewünschte Ergebnis erzielen, beispielsweise mit einem einfachen (Prä-)Transpiler für den Pipe-Operator, der die TS-Syntax versteht und sein stark typisiertes Äquivalent der Anweisung erzeugt. Es würde mit Typprüfung und so weiter kompilieren.

Eine Webpack-Konfiguration dafür könnte etwa so aussehen:

module: {
        rules: [
            { test: /\.ts$/, loader: 'ts-pipe-operator', enforce: 'pre' },
            { test: /\.ts$/, loader: 'ts-loader' },
            ...
        ]
 }

Die einzige Herausforderung, auf die @garkin hingewiesen transpilierte Teile nicht mit der ursprünglichen Quelldatei korrelieren könnte Syntax aktiviert oder so).

Wenn wir einen NFR (oder gibt es vielleicht schon einen?) Rest der Community und vor allem ohne zusätzliche Komplexität für das Kernteam.


Außerdem kann ich nicht sagen, inwieweit #13940 damit zusammenhängt, aber es ist anscheinend ein guter Anfang für komplexere Plugins. Es scheint mir jedoch, dass der Source-Map-Ansatz eine noch viel einfachere Alternative ist, da ein minimalistischer (Prä-)Transpiler den Projektkontext in den meisten Fällen nicht benötigen würde, da es ziemlich einfach wäre, einfach die Typnotationsblöcke (falls vorhanden) aus dem zu extrahieren Anweisungs-Rohtext und schreiben Sie ihn dann so um, dass die Ablaufsteuerung die spezifischen E/A-Typen für den transpilierten Teil implizieren kann.


Zu guter Letzt, könnte mich bitte jemand auf den _offiziellen_ Thread (falls vorhanden) bezüglich dieser Art von Plugins hinweisen?

Ich muss sagen, dass ich die ruhige Art der Einführung neuer Vorschläge wirklich schätze und die monolithischen Typescript- und LessCSS-Tools viel mehr bevorzuge als Flow+Babel und Post-CSS-Sonder-Plugins Olympic.

Es ist eine Anpassbarkeit und eine Geschwindigkeit, mit der neue Funktionen aufgrund von aufgeblähter Fragmentierung und einem Fachgebiet erhalten werden.

Der Pfeifenoperator ist wie eine Einstiegsdroge in die funktionale Welt, er bringt mich dazu, seltsame Dinge zu sagen und zu wünschen.

Es gibt also bereits #14419 und sogar einige nützliche praktische Implikationen . Sollte nicht schwer sein, diese mit ts-loader .

tsconfig.json Transformer-Integration (und damit Language Service API, nicht nur angepasst tsc ) #14654 wurde _kurzfristig_ abgelehnt.

11976 diskutiert ein Sprachdienst-Plugin, das wie ein Linting-Only-Tool aussieht.

16607 schlägt eine Erweiterung dieser Plugins auf die Transformatoren vor.

@PublicParadise oder einfach flow Lodash oder pipe Rambda verwenden?

Wie auch immer, es wäre so toll zu sehen, dass es in TS unterstützt wird. Ich liebe die funktionalen Muster, die JS unterstützt (insbesondere mit der Typinferenz von TS), aber einige Muster lesen sich nicht sehr gut. Dies wäre enorm, da sich große TS-Bibliotheken wie RxJS und IxJS in Richtung einer punktfreien funktionalen Komposition über die Prototyperweiterung/Vererbung bewegen, es sorgt für viel besseres Tree-Shaking und Unterstützung für benutzerdefinierte Operatoren.

@felixfbecker Du meinst Ramdas pipe ? Ich muss es noch einmal versuchen, aber historisch gesehen ist Ramda eine JS-first Lib, es ist sehr dynamisch und schwer zu tippen (wie lodash), was durch die Tatsache verschlimmert wird, dass TS früher viele Probleme hatte, von Funktionsrückgabewerten abzuleiten (es könnte gewesen sein) vor kurzem behoben, aber nicht sicher)
Ich verwende lodash da es schlecht gestaltet ist und veränderliche und unveränderliche Funktionen in einem großen Namensraum mischt.

Es funktioniert tatsächlich anständig gut, wenn Ihre Funktionen und Ketten nicht super verrückt sind:

https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b67c928904f03d0911c99ab938b14bc2e59cad40/types/lodash/index.d.ts#L7819 -L7855

Es funktioniert eigentlich ganz gut, wenn deine Funktionen und Ketten nicht super verrückt sind

Lassen Sie mich dort "nicht super verrückt" qualifizieren: Dinge brechen zusammen, wenn Ihre Funktionen Generika haben (siehe https://github.com/types/npm-ramda/issues/86), zB R.pipe(R.identity) .

Lassen Sie uns auch klarstellen, dass der Vorschlag Phase 1 ist. Das Kernteam scheut sich noch mehr, Dinge vor Phase 3 einzuführen. Dekorateure sind ein Teil des Beispiels. Obwohl sie als _experimentell_ markiert waren, haben wir alle dieses Flag aktiviert und unseren gesamten Produktionscode mit ihnen geschrieben. Der Vorschlag hat sich nun herumgesprochen und es gibt einige grundlegende grundlegende Änderungen in der Syntax und Semantik, die bedeuten werden, dass wir alle unseren Code umgestalten müssen, was das Kernteam in eine schwierige Situation bringt, denn wenn sie _nur_ das Finale unterstützen Syntax, als alle an dem Tag kaputt sind, an dem sie es veröffentlichen, oder wenn sie das alte Zeug behalten, können andere Änderungen im Compiler es schwierig machen, die beiden Syntaxen zu unterstützen, und schließlich möchten Sie das alte Zeug loswerden, aber wenn.. . 💥

Das Beste, was Sie mit standardbasierten Funktionen wie dieser tun können, ist, hier nicht über die Unterstützung oder den Mangel von TypeScript zu diskutieren das oben verlinkte Angebotsgespräch auf GitHub. Je schneller die Semantik aufgelöst wird und je schneller Phase 3 erreicht wird, desto schneller können wir alle schöne Dinge haben!

Jetzt, da rxjs vermietbare Operatoren hat, wäre dies eine noch großartigere Funktion in Typescript
https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md

Können wir jemanden vom TS-Team haben, der etwas Licht in diese Anfrage bringt?

Sie haben es mit ES Next und Suggestion getaggt ... Ich kann Ihnen Kapitel und Verse an anderen Stellen zitieren, an denen sie Kommentare zu den Vorschlägen von ES Next abgegeben haben und wann und wie sie sie umsetzen ...

Ein Kommentar von ihnen ändert nichts. Glaubst du, sie arbeiten heimlich hinter den Kulissen daran und warten darauf, die Community davon zu überzeugen? Sie geben oft keinen Beitrag zu einem Thema, wenn es nichts hinzuzufügen gibt... Es gibt nichts hinzuzufügen zu dem, was bereits gesagt wurde.

An dieser Stelle glaube ich, dass es so nützlich wäre, Plugins zu haben, die die Sprache erweitern. Das Hinzufügen von Funktionen, die nicht zum Kern der Sprache gehören, sind Teil dieser Plugins.

@aminpaks Ich finde die Idee nicht wirklich

Da Plugins ein Verhalten auf Typebene implizieren würden, wird es schwierig, die Bedeutung von Programmen zu verstehen, und die Handhabung von Abhängigkeiten auf Quellebene würde eine Reihe komplexer, aber sehr nützlicher Funktionen erfordern, die TypeScript derzeit fehlt.

So sehr ich es _liebe_, dass dies überall möglich wäre, freue ich mich, dass TS bei der Implementierung neuer Features zurückhaltender vorgeht und sich an Standards hält. Diese Haltung macht TS insgesamt attraktiver für Leute wie mich, denen es sehr wichtig ist, vom Standard abzuweichen, aber die erweiterten Funktionen, die die Transpilation bietet, vor der Einführung des Browsers / der JS-Engine (aber nicht unbedingt vor der Standardisierung) genießen. Es ist ein heikler Balanceakt.

Persönlich bin ich nicht für den Pipeline-Betreiber auf Kosten des Binde-Betreibers. Es kommt wirklich auf die Lesbarkeit an.

Gegeben:

function* where<T>(items: Iterable<T>, predicate: (item:T)=>boolean){
  for (let item of items){
    if(predicate(item)) yield item;
  }
}

Bind-Op:

[1,2,3]::where(x=>x>2)

Pipeline-Operation:

[1,2,3]|>(_)=>where(_,x=>x>2)

ts-team hat Recht, sich erst in Stufe 3 die Mühe zu machen; und selbst dann können Stufe-3-Vorschläge noch zurückgezogen werden (zB SIMD). Es ist jedoch eine Schande, dass wir keine Plugins haben können - das "Risiko" wird an den einzelnen Entwickler weitergegeben. Es gibt auch viele andere Anwendungsfälle für Plugins, nicht zuletzt um Dinge wie .vue Dateien zu unterstützen, die Typoskript enthalten.

@MeirionHughes Ich stimme zu. Ich hätte zwar lieber den Pipeline-Operator als überhaupt keinen Zucker, aber er ist von Sprachen inspiriert, in denen Funktionen automatisch gecurry werden und Bibliotheken darauf aufgebaut sind, dies zu nutzen. Außerdem wird davon ausgegangen, dass Pipelinemethoden _keine_ Mitglieder der Pipelinewerte sind.

Dann hättest du

function where<T>(predicate: (item: T) => boolean): (items: Itererable<T>) => Itererable<T> {
  return function* () {
    for (const item of items) if (predicate(item)) yield item;
  };
}

function select<T, R>(projection: (item: T) => R): (items: Itererable<T>) => Itererable<R> {
  return function* () {
    for (const item of items) yield projection(item);
  };
}

und dann würdest du schreiben

[1, 2, 3] |> where(x => x > 2) |> select(x => x ** 2);

Da JavaScript jedoch keine Auto-Curry-Funktionen hat und kann, scheint es nur mit Bibliotheken gut zu funktionieren, die auf Currying ausgelegt sind.

Ich könnte mich darin irren, ich bin nicht sehr aktuell bezüglich des Vorschlags.

Dann könnte eine neue Bibliothek, die standardmäßig Curry-Utility-Funktionen bereitstellt, der neue Standard werden :p

@AlexGalays Ich denke, das ist wahrscheinlich, wenn dies besteht. Solange es nicht Teil einer subversiven Handlung ist, JavaScript in OCaml zu verwandeln, ist alles gut.

@MeirionHughes dein Beispiel ist nicht korrekt. Ihre Funktion where verwendet this überhaupt nicht, daher würde der Bindeoperator nicht funktionieren. Der Bindeoperator hat auch viele offene Fragen zur Typsicherheit. Würde where this wie eine Klassenmethode von this ? Wenn ja, dann ist die Änderung von Privateigentum plötzlich eine schwerwiegende Änderung, die den Zweck von Privateigentum vollständig verfehlt.
Sie geben auch an, dass die Syntax weniger lesbar ist, lassen aber beispielsweise die Klammern in Ihrem Bindeoperator-Beispiel weg, fügen jedoch nicht benötigte Klammern im Pipeline-Beispiel hinzu. Und der Pipeline-Operator funktioniert natürlich überhaupt nicht mit Funktionen, die zum Binden geschrieben wurden, aber er funktioniert gut für Curry-Funktionen wie rxjs-Operatoren, Ramda oder Lodash/fp.

@aluanhaddad Neben all den fp-Bibliotheken ist RxJS ein Beispiel für eine weit verbreitete Bibliothek, die von Operatoren auf Prototypen (die viele Probleme haben, hauptsächlich in Bezug auf Tree-Shaking und generische Typsicherheit) zu Operatoren als Curry-Funktionen übergegangen ist. Die meisten Bibliotheken wählen diesen Weg wahrscheinlich im Moment nicht, _weil_ wir keine gute Syntax dafür haben.

@felixfbecker Sie haben Recht und das Beispiel von @aluanhaddad , das die resultierenden Funktionen

Hat jemand darüber nachgedacht oder implementiert einen benutzerdefinierten Transformer, um die Pipeline-Unterstützung etwas früher zu erhalten? So wie es aussieht, könnte dies über einen benutzerdefinierten Transformator erfolgen, der einfach Babel _nur_ den Pipeline-Teil selbst transpiliert. Sie könnten es dann ausführen über: https://github.com/cevek/ttypescript

Ist das eine Möglichkeit? Verwenden Sie benutzerdefinierte Transformationen, um die von Babel unterstützte Syntax zu verwenden, während Dinge wie die TypeScripts-Tools funktionieren?

Könnte sein? Es gibt eine Voreinstellung, die sich nur mit den 0-2 Vorschlägen befasst: https://www.npmjs.com/package/babel-preset-proposal-typescript - das bedeutet, dass Sie dies eingeben, bevor Sie es an typescript senden. Sie sind jedoch wahrscheinlich borked. Mit https://github.com/cevek/ttypescript#visual -studio-code könnten Sie jedoch damit durchkommen.

@MeirionHughes freut mich, dass das hilfreich war ❤️.
Jetzt brauchen wir nur noch #6606, um Methoden beliebiger Prototypen in Curry-Funktionen umzuwandeln!

TypeScript ist jetzt eine Babel-Transformation, ich denke, es sollte eine Möglichkeit geben, die Pipeline-Entzuckerung vor dem TypeScript-Durchlauf zu sequenzieren. Ich habe jedoch keine Ahnung, wie Sie das mit dem Sprachserver zum Laufen bringen.

Ich habe eine selbst gehostete Implementierung für TS #22816 hinzugefügt

Als einer der Leute, die auf den Pipeline-Operator drängen, bitte ich Sie: Bitte implementieren Sie dies _nicht_ in TypeScript, bis es weiter fortgeschritten ist. Wir diskutieren immer noch über zwei mögliche Vorschläge, die im Grunde nicht miteinander kompatibel sind, also bettelt TypeScript um eine Welt, die schmerzhaft ist, wenn es dies zu früh implementiert.

Wenn Sie an diesem Vorschlag interessiert sind, schauen Sie sich das Repo hier an und machen Sie mit: https://github.com/tc39/proposal-pipeline-operator/ Wir freuen uns über Ihr Feedback! Und wir arbeiten an Babel-Plugins für die unterschiedlichen Vorschläge, damit Sie die Möglichkeit haben, sie in Ihren (Nicht-TypeScript-)Projekten auszuprobieren.

Aber der Vorschlag ist noch nicht bereit, in so etwas wie TypeScript zu landen.

Wir werden das definitiv nicht zusammenführen.

Könnten wir so etwas wie https://github.com/babel/babel-eslint haben , das es uns ermöglicht, von Babel unterstützte Funktionen weiterhin zu verwenden, und die Typprüfung funktioniert, nachdem von TypeScript nicht unterstützte Funktionen entfernt wurden?

@masaeedu Ja! Dies

@MeirionHughes mit dem

[1,2,3] |> where(?, x=>x>2)

@bernatmv : fwiw es gibt etwas in der Nähe, das heute funktioniert.

@tycho01 Aber nicht in TypeScript, nicht bis es 2.8 Eingaben bekommt: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/25067

@jeremejevs @bernatmv tatsächlich wurde R.__ mit Codegen in npm-ramda eingegeben . Bessere Möglichkeiten mit 2.8 Willkommen!

Ich bin etwas neu in Javascript und TypeScript (2 Wochen), also bitte verzeihen Sie mir, wenn es eine einfachere Lösung gibt. Aber unten ist, was ich mir in Abwesenheit eines Pipeline-Betreibers ausgedacht habe. Ich habe ursprünglich versucht, mehrere Überladungen von pipe , die mit 2, 3, 4 usw. Typparametern funktionierten, konnte aber nicht herausfinden, wie die TypeScript-Überladungsauflösung wie in C# funktioniert. Wir könnten verschiedene Funktionen pipe1<A,B> , pipe2<A,B,C> und pipe3<A,B,C,D> aber dies wäre schwierig, da Sie den Funktionsnamen basierend auf der Anzahl der Argumente auswählen müssten gesucht. Gibt es eine einfachere typsichere Lösung als die, die ich unten vorgeschlagen habe? Gibt es eine rekursive Typdefinition, die eine unbegrenzte Anzahl von Parametern akzeptieren könnte? Verwende ich Konditionsarten richtig?

type LastOf<
    A,
    B=never,
    C=never,
    D=never,
    E=never,
    F=never,
    G=never,
    H=never,
    I=never,
    J=never> =
    [B] extends [never] ? A :
    [C] extends [never] ? B :
    [D] extends [never] ? C :
    [E] extends [never] ? D :
    [F] extends [never] ? E :
    [G] extends [never] ? F :
    [H] extends [never] ? G :
    [I] extends [never] ? H :
    [J] extends [never] ? I :
    J;

export function pipe<A, B, C=never, D=never, E=never, F=never, G=never, H=never, I=never, J=never>(
    a: A,
    mapA: (a: A) => B,
    mapB?: (b: B) => C,
    mapC?: (c: C) => D,
    mapD?: (d: D) => E,
    mapE?: (e: E) => F,
    mapF?: (f: F) => G,
    mapG?: (g: G) => H,
    mapH?: (h: H) => I,
    mapI?: (i: I) => J
): LastOf<A, B, C, D, E, F, G, H, I, J> {
    if (mapB === undefined) {
        return mapA(a) as LastOf<A, B, C, D, E, F, G, H, I, J>;
    }
    if (mapC === undefined) {
        return mapB(mapA(a)) as LastOf<A, B, C, D, E, F, G, H, I, J>;
    }
    if (mapD === undefined) {
        return mapC(mapB(mapA(a))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
    }
    if (mapE === undefined) {
        return mapD(mapC(mapB(mapA(a)))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
    }
    if (mapF === undefined) {
        return mapE(mapD(mapC(mapB(mapA(a))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
    }
    if (mapG === undefined) {
        return mapF(mapE(mapD(mapC(mapB(mapA(a)))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
    }
    if (mapH === undefined) {
        return mapG(mapF(mapE(mapD(mapC(mapB(mapA(a))))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
    }
    if (mapI === undefined) {
        return mapH(mapG(mapF(mapE(mapD(mapC(mapB(mapA(a)))))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
    }
    return mapI(mapH(mapG(mapF(mapE(mapD(mapC(mapB(mapA(a))))))))) as LastOf<A, B, C, D, E, F, G, H, I, J>;
}

test("map once", () => {
    const result = pipe(
        2,
        i => i * 10);
    expect(result).toBe(20);
});

test("map twice", () => {
    const result = pipe(
        2,
        i => i * 10,
        i => `the answer is ${i}`);
    expect(result).toBe('the answer is 20');
});

test("map three times", () => {
    const result = pipe(
        2,
        i => i * 10,
        i => -i,
        i => ({ a: i, b: -i }));
    expect(result).toEqual({ a: -20, b: 20 });
});

Ich dachte, lodash/fp's _.flow hätte das schon abgetippt?

Am Mittwoch, den 9. Mai 2018, 22:19 Uhr jmagaram, schrieb [email protected] :

Ich bin etwas neu in Javascript und TypeScript (2 Wochen), also bitte verzeihen
mich, wenn es da draußen eine einfachere Lösung gibt. Aber unten ist das, was mir eingefallen ist
mit in Abwesenheit eines Pipeline-Betreibers. Ich habe ursprünglich versucht, zu haben
mehrere Überlastungen von Rohren, die mit Typ 2, 3, 4 usw. funktionierten
Parameter, konnte aber nicht herausfinden, wie man die TypeScript-Überladung erhält
Auflösung, um wie in C# zu funktionieren. Wir könnten verschiedene Funktionen haben
pipe1 , pipe2 und pipe3, aber das wäre schwer zu machen arbeiten, da Sie den Funktionsnamen basierend auf der Anzahl auswählen müssenArgumente, die Sie wollten.
Gibt es eine rekursive Typdefinition, die ein akzeptieren könnte?unbegrenzte Anzahl von Parametern?

Typ LastOf = [B] verlängert [nie] ?
B :[D] verlängert [nie] ?
D :[F] verlängert [nie] ?

Funktionsrohr ( a: A,mapA: (a: A) => B,mapB?: (b: B) => C,mapC?: (c: C) => D,mapD?: (d: D) => E,mapE?: (e: E) => F): LastOf { const b = mapA(a);wechseln (mapB) {Fall undefiniert: Rückgabe b als LastOf ; Ursprünglich: {const c = mapB(b);wechseln (mapC) {Fall undefiniert: Rückgabe c als LastOf ; Ursprünglich: {const d = mapC(c);Schalter (mapD) {Fall undefiniert: Rückgabe d als LastOf ; Ursprünglich: {const e = mapD(d);wechseln (mapE) {Fall undefiniert: e als LastOf zurückgeben ;Standardwert: mapE(e) als LastOf zurückgeben ; }}}}}}}}

test("einmal zuordnen", () => {
const result = pipe(
2,
ich => ich * 10);
erwarten(Ergebnis).toBe(20);
});

test("zweimal abbilden", () => {
const result = pipe(
2,
ich => ich * 10,
ich => the answer is ${i} );
Expect(result).toBe('die Antwort ist 20');
});

test("dreimal zuordnen", () => {
const result = pipe(
2,
ich => ich * 10,
ich => -ich,
i => ({a: i, b: -i}));
erwarten(Ergebnis).toEqual({ a: -20, b: 20 });
});


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-387878691 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAZQTLm6LrWe5KVx4aGBFUd4yRUHkkrZks5tw11cgaJpZM4OzVEg
.

Ich habe mir gerade lodash angesehen und Sie haben Recht - die Flow-Funktion akzeptiert viele Parameter und ist stark typisiert. Es sieht nicht so aus, als wäre es in reinem TypeScript gemacht. Sie verwenden eine Typdefinitionsdatei für alle Überladungen. Ich bin mir nicht sicher, ob dies besser oder schlechter ist, als zu versuchen, alles in TypeScript zu tun.

@jmagaram all TS macht es im Allgemeinen aufgrund von Schlussfolgerungen einfacher, aber wenn es funktioniert, funktioniert es.

@jmagaram Eine etwas einfachere reine Typoskript-Alternative könnte etwa so aussehen.

interface IPipe<T> {
    readonly value: () => T;
    chain<R>(fn: (x: T) => R): IPipe<R>;
}

function pipe<T>(val: T): IPipe<T> {
    return {
        chain: fn => pipe(fn(val)),
        value: () => val
    };
}

Die Verwendung wäre immer noch ziemlich sauber und stark typisiert.

pipe(["Hello", "There"])
    .chain(map(x => `${x}!`))
    .chain(xs => {
        ...
    })
    .value()

Ich würde mich sehr über die Möglichkeit freuen, benutzerdefinierte Operatoren hinzuzufügen. F# hat dafür einen schönen Ansatz.

In der Zwischenzeit ist hier ein einfacherer Ansatz ohne die Umhüllung:

function pipe<T1>(first:T1):T1
function pipe<T1, T2>(first:T1, second:(a:T1) => T2):T2
function pipe<T1, T2, T3>(first:T1, second:(a:T1) => T2, third:(a:T2) => T3):T3
function pipe<T1, T2, T3, T4>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4):T4
function pipe<T1, T2, T3, T4, T5>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5):T5
function pipe<T1, T2, T3, T4, T5, T6>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6):T6
function pipe<T1, T2, T3, T4, T5, T6, T7>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6, seventh:(a:T6)=>T7):T7
function pipe<T1, T2, T3, T4, T5, T6, T7, T8>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6, seventh:(a:T6)=>T7, eigth:(a:T7)=>T8):T8
function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6, seventh:(a:T6)=>T7, eigth:(a:T7)=>T8, ninth:(a:T8)=>T9):T9
function pipe<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(first:()=>T1, second:(a:T1)=>T2, third:(a:T2)=>T3, fourth:(a:T3)=>T4, fifth:(a:T4)=>T5, sixth:(a:T5)=>T6, seventh:(a:T6)=>T7, eigth:(a:T7)=>T8, ninth:(a:T8)=>T9, tenth:(a:T9)=>T10):T10
function pipe(first:any, ...args:Function[]):any {
    return (
        args && args.length 
        ? args.reduce(
            (result, next) => next(result),
            first instanceof Function ? first() : first
        )
        : first instanceof Function ? first() : first
    );
}

Das gibt:
ts-pipe-example
( weitere Infos siehe hier )

Das heißt, @graingert +1 Sie haben Recht: lodash hat dies bereits für die Komposition (aber nicht für die Pipe):

const getUpperName = 
   _.flow(
      (p: Person) => `${p.FirstName} ${p.LastName}`,
      (s: string) => s.toUpper()
   )

Alternativ können Sie dem Object.prototype stattdessen Pipe hinzufügen:

Object.prototype.pipe = function<Self, Result>(this:Self, next:(value:Self) => Result):Result {
    return next(this)
}

Dies ermöglicht stattdessen:
capture
( weitere Infos siehe hier )

Hoffe das hilft anderen!

Es ist in Firefox unter dem Kompilier-Flag --enable-pipeline-operator gelandet.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Pipeline_operator

Eine Schweigeminute für den gefallenen Helden, den Bindeoperator :: , geschlossen zugunsten des Bösen |> 😢

Nun, ich denke, es liegt im Auge des Betrachters, denn ich bevorzuge |> :D

Heil dem König!

Und hier dachte ich, es wäre ein Wunschtraum

Pipeline ist im Wesentlichen ein einfacher Anwendungsfall der Identity Monad. Außerdem ist pipe normalerweise umgekehrt compose , während pipeline eher wie ein pipe ist, das sofort aufgerufen wird.

Wie auch immer, ich freue mich darauf, dies in Typoskript zu sehen.

Obwohl es hilfreich wäre, eine Pipeline zu haben, denke ich, dass es möglich wäre, benutzerdefinierte Operatoren (Funktionen, deren Name Sonderzeichen enthalten kann und deren erster Parameter auf der linken Seite steht) über einen Compiler-Transformator zu definieren. Hat jemand Interesse, dies mit mir auszuprobieren, oder hat Hintergrundinformationen dazu?

Am Freitag, 10. August 2018, 02:53 Uhr schrieb Babak [email protected] :

Pipeline ist im Wesentlichen ein einfacher Anwendungsfall der Identity Monad. Ebenfalls,
Rohr wird normalerweise umgekehrt zusammengesetzt, während die Pipeline eher wie ein Rohr ist
das wird gleich aufgerufen.

Wie auch immer, ich freue mich darauf, dies in Typoskript zu sehen.


Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411824741 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg
.

--

Infix-Funktionen ftw

Am Do, 9. August 2018, 23:35 Uhr Ben Beattie-Hood, [email protected]
schrieb:

Obwohl es hilfreich wäre, eine Pipeline zu haben, denke ich, dass es möglich wäre,
bieten die Möglichkeit, benutzerdefinierte Operatoren zu definieren (Funktionen, deren Name
Sonderzeichen einschließen und deren erster Parameter auf der linken Seite steht) über a
Compiler-Transformator. Wer hat Interesse, das mit mir auszuprobieren, oder hat
einige Hintergründe dazu?

Am Freitag, 10. August 2018, 02:53 Uhr schrieb Babak [email protected] :

Pipeline ist im Wesentlichen ein einfacher Anwendungsfall der Identity Monad. Ebenfalls,
Rohr wird normalerweise umgekehrt zusammengesetzt, während die Pipeline eher wie ein Rohr ist
das wird gleich aufgerufen.

Wie auch immer, ich freue mich darauf, dies in Typoskript zu sehen.


Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
<
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment -411824741
,
oder den Thread stumm schalten
<
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg

.

--


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411919587 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AAZQTHHFbVY5uGCWl-La_P-HF7UN6xPsks5uPLk8gaJpZM4OzVEg
.

die Idee von Infix-Funktionen für Typoskript ist fast so alt wie Typoskript: https://github.com/Microsoft/TypeScript/issues/2319

Ich weiß, dass viele Leute dies wirklich wollen, aber ich glaube, TypeScript sollte keinen zusätzlichen Operator implementieren, solange sie sich nicht in Stufe 3 befinden. Dinge können sich ändern und natürlich gibt es einige Ausnahmen.

Ich denke, es wäre einen Versuch wert, es als Compiler-Transformator zu versuchen, nur um der Community zu ermöglichen, die Idee zu erkunden und die Popularität zu messen. Es ist ein gut definiertes Feature in anderen funktionalen Sprachen, daher kann es ziemlich sicher sein, es zu erkunden.

@BenBeattieHood Wir sind dabei, dies in Babel zu implementieren, sodass Sie es dort testen können. Wenn Sie es in einem Compiler-Transformator testen, sehen Sie sich auf jeden Fall die aktuellen Vorschläge an , da wir einige Formen des Pipeline-Operators in Betracht ziehen.

Ich denke, es müsste viel darüber nachgedacht werden, wie es verwendet wird; speziell in Bezug auf das Tippen von Dingen wie:

function where<T>(predicate: (x: T) => boolean) {
  return function* (items: Iterable<T>): Iterable<T> {
    for (const item of items) {
      if (predicate(item)) {
        yield item;
      }
    }
  };
}

[1, 2, 3] |> where(x=>x> 1)

im Moment kann mit where(x => x > 1)([1,2,3]) nicht abgeleitet werden, was x ist. Das oben Gesagte ist ein Grund, warum ich gehofft habe, dass die Operation :: gewinnen würde, weil es (auf den ersten Blick) für Typoskript viel einfacher zu sein scheint, abzuleiten, was this ist

Oder wir können es anders sehen: Sollte es veröffentlicht werden, werden einige der Inferenzprobleme von TS priorisiert 👍

Wenn Sie die Spec- und Babel-News verfolgen, ist die Spezifikation noch nicht festgelegt. Es gibt 2 Vorschläge. Ich bin mir sicher, dass das Typoskript-Team Unterstützung hinzufügen wird, wenn die Spezifikation fertiggestellt ist

Infix-Funktionen ftw

iirc JS nennt diese "Methoden".

iirc JS nennt diese "Methoden"

@tycho01 Dein Kommentar ist wahrscheinlich

@BenBeattieHood Wir sind dabei, dies in Babel zu implementieren, sodass Sie es dort testen können. Wenn Sie es in einem Compiler-Transformator testen, sehen Sie sich auf jeden Fall die aktuellen Vorschläge an, da es einige Formen des Pipeline-Operators gibt, die wir in Betracht ziehen.

Der Babel-Parser unterstützt jetzt einen intelligenten Pipeline-Vorschlag.

https://github.com/babel/babel/pull/8289

Irgendwelche Updates?

Irgendwelche Updates?

🤦‍♂️ TypeScript implementiert Vorschläge erst, wenn sie Stufe 3 erreichen. Der Pipeline-Betreiber befindet sich derzeit in Stufe 1 und hat schwerwiegende Probleme. Diese Informationen wurden in diesem Thread mehrmals bereitgestellt.

ein Beispiel für ernste Probleme bitte?

könnte sein...

⚠ Warnung: Die Details der Pipeline-Syntax sind derzeit ungeklärt. Es werden zwei konkurrierende Vorschläge geprüft.

Ja, das halte ich für ein ernstes Problem.

Ich werde diesen hier sperren, da alle Threads im Status zu drehen .

Klingeln!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

MartynasZilinskas picture MartynasZilinskas  ·  3Kommentare

dlaberge picture dlaberge  ·  3Kommentare

jbondc picture jbondc  ·  3Kommentare

uber5001 picture uber5001  ·  3Kommentare

zhuravlikjb picture zhuravlikjb  ·  3Kommentare