Typescript: Soutenir l'opérateur de pipeline ES Next "|>" proposé

Créé le 10 août 2017  ·  79Commentaires  ·  Source: microsoft/TypeScript

ES Next Suggestion Waiting for TC39

Commentaire le plus utile

C'est à l'étape 1 maintenant

Tous les 79 commentaires

Ma proposition préférée :( De nos jours, nous pouvons vraiment écrire des programmes gratuits this .

Pour référence, la proposition TC39 : https://github.com/tc39/proposal-pipeline-operator

Non pas que la proposition ne soit même pas encore au stade 0. Si jamais il est ajouté à la sémantique du langage et d'autres détails changeront probablement.

Ce serait une première, je pense (à côté de certains vieux comme Enum et le système de modules), mais la mise en œuvre du script dactylographié pourrait-elle lui donner plus de visibilité et augmenter la demande dans le reste de l'écosystème ecma?

Je voulais juste partager une solution de contournement pour l'opérateur de pipeline manquant inspirée de https://vanslaars.io/post/create-pipe-function/...

SyncPipe avec réduction synchrone

// 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 avec réduction asynchrone

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

Canalisation avec réduction asynchrone (simplifiée)

J'utilise celui-ci la plupart du temps :

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

J'espère que vous trouverez cela utile!

@PublicParadise beaucoup trop de passe-

Bien que j'aimerais certainement voir une variante de cet opérateur dans le langage, le besoin perçu provient de deux limitations différentes d'ECMAScript dans sa forme actuelle.

Le premier est très difficile à contourner ou même à résoudre dans le langage : l'incapacité à étendre les objets intégrés de manière hygiénique.

La seconde n'a cependant pas du tout besoin de support de niveau de langue et pourrait en fait être rectifiée : la bibliothèque standard peut gentiment être qualifiée d'anémique.

Maximalement Minimal est un échec complet.

Pourquoi faut-il des mois et des mois d'argumentation pour obtenir Array.prototype.flatMap dans la langue ?

C'est une méthode et elle aurait dû être là depuis le début et il devrait être évident qu'elle devrait être ajoutée.

Peut-être que Array.prototype aura une méthode groupBy dans 6 ans.

À l'heure actuelle, il existe quelques implémentations babel, qui, espérons-le, aideront le long de la proposition TC39 :

C'est à l'étape 1 maintenant

Alors, des chances pour que cette beauté entre dans TS ? Ce serait en ligne avec F#. <3

Bien qu'il existe des exceptions, lorsqu'une proposition est _importante_ pour TypeScript et les types, les propositions ne sont généralement pas mises en œuvre avant d'atteindre TC39 Stage 3 dans TypeScript, car elles ne sont pas suffisamment stables pour garantir qu'il n'y aura pas de ruptures et de régressions importantes.

Bien qu'aucun membre de l'équipe principale n'ait encore commenté ce problème, il ne serait pas, à mon avis, assez _important_ pour être pris en compte pour la mise en œuvre avant l'étape 3. Le meilleur objectif est de soutenir le champion et la proposition au TC39.

Si seulement TS avait la possibilité de simplement diriger cet opérateur pour permettre à un babel avec des plugins de le gérer.
Ou avait ses propres plugins de syntaxe, comme le font post-css. Plusieurs années d'attente pour un opérateur primitif, c'est tout simplement trop.

@garkin : Le défi ici est que TS doit comprendre le code pour faire son travail de sécurité de type, qui ne se combine pas bien avec un code aléatoire qu'il ne comprend pas. À moins qu'il ne s'agisse d'obtenir des macros (#4892), auquel cas il se contenterait de compiler pour coder qu'il comprend. Mais je ne m'attendrais pas encore à ce que cela figure sur la feuille de route, car il est encore difficile de saisir de nombreux éléments de la bibliothèque standard.

Maintenant que Babel comprend le tapuscrit, vous pouvez le faire passer par Babel alors
manuscrit

Le 26 octobre 2017 à 19h01, "Tycho Grouwstra" [email protected] a écrit :

@garkin https://github.com/garkin : Le défi ici est que TS doit
comprendre le code pour faire son travail de sécurité de type, ce qui ne
se combine bien avec un code aléatoire qu'il ne comprend pas. A moins que ce ne soit pour obtenir
macros (#4892 https://github.com/Microsoft/TypeScript/issues/4892 ), dans
auquel cas il ne ferait que compiler pour coder qu'il comprend. Mais je ne voudrais pas
attendez-vous à ce que sur la feuille de route tout de suite, car pas mal de morceaux de la norme
bibliothèque sont toujours difficiles à taper atm.

-
Vous recevez ceci parce que vous avez créé le fil.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339748284 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAZQTO6UiVHbrM6SRwaBhm8obaa3R7e9ks5swMkCgaJpZM4OzVEg
.

Maintenant que Babel comprend le tapuscrit, vous pouvez le faire passer par Babel alors
manuscrit

Deux fois le temps de construction cependant :p

Ce serait bien si tapscript n'était qu'un plugin Babel, alors vous n'auriez pas besoin de
passer par les deux programmes

Le 26 octobre 2017 à 20h16, "AlexGalays" [email protected] a écrit :

Maintenant que Babel comprend le tapuscrit, vous pouvez le faire passer par Babel alors
manuscrit

Deux fois le temps de construction cependant :p

-
Vous recevez ceci parce que vous avez créé le fil.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339769856 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAZQTEArBw8jj0BcZFM2yLj5ErfbtNrgks5swNqagaJpZM4OzVEg
.

@graingert : C'est une bonne option à avoir, je vais enquêter là-
Malheureusement, cela ne fonctionnera pas avec l'API de service de langage dactylographié utilisée par VisualStudioCode, Webstorm et d'autres IDE.

En ce qui concerne les "plugins TS", on pourrait facilement obtenir le résultat souhaité avec, disons, un simple (pré)transpilateur pour l'opérateur de pipe qui comprend la syntaxe TS et produit son équivalent typé fort de l'instruction. Il compilerait très bien avec la vérification de type et ainsi de suite.

Une configuration Webpack pour cela pourrait ressembler à ceci :

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

Le seul défi, comme l'a souligné @garkin , est que le service TS ne serait pas en mesure de corréler les parties transpilées au fichier source d'origine, alors les IDE qui utilisent le service ne fonctionneraient pas correctement même s'ils reconnaissent déjà l'opérateur (ES Next syntaxe activée ou quelque chose).

Peut-être que si nous créons un NFR (ou peut-être y en a-t-il déjà un ?) reste de la communauté et, surtout, sans ajouter plus de complexité à gérer pour l'équipe de base.


De plus, je ne peux pas dire à quel point #13940 est lié à cela, mais c'est apparemment un bon début vers des plugins plus complexes. Cependant, il me semble que l'approche de la carte source reste une alternative beaucoup plus simple, car un (pré)transpilateur minimaliste n'aurait pas besoin du contexte du projet dans la plupart des cas, car il serait assez facile d'extraire simplement les blocs de notation de type (le cas échéant) du texte brut de l'instruction, puis réécrivez-le de manière à ce que le flux de contrôle puisse impliquer les types d'E/S spécifiques pour la partie transpilée.


Enfin, est-ce que quelqu'un pourrait m'indiquer le fil _official_ (le cas échéant) concernant ce type de plugins ?

Je dois dire que j'apprécie vraiment la manière calme d'introduire de nouvelles propositions et que je préfère beaucoup plus les outils monolithiques Typescript et LessCSS, que les jeux olympiques de plugins spéciaux Flow+Babel et Post-CSS.

Il s'agit d'une personnalisation et d'une vitesse d'obtention de nouvelles fonctionnalités en termes de coût de fragmentation des ballonnements et d'un domaine d'expertise.

L'opérateur du tuyau est comme un médicament d'entrée dans le monde fonctionnel, il me fait dire et souhaiter des choses étranges.

Donc, il y a déjà #14419 et même quelques implications pratiques utiles. Ne devrait pas être difficile d'intégrer ceux avec ts-loader .

tsconfig.json intégration des tsc ) #14654 a été refusé _à court terme_.

11976 discute d'un plugin Language Service, qui ressemble à un outil de linting uniquement.

16607 proposant l'extension de ces plugins aux transformateurs.

@PublicParadise ou utilisez simplement les flow lodash ou les pipe Rambda ?

de toute façon, ce serait tellement génial de voir être pris en charge dans TS. J'adore les modèles fonctionnels pris en charge par JS (en particulier avec l'inférence de type TS), mais certains modèles ne se lisent pas très bien. Ce serait énorme car les grandes bibliothèques TS comme RxJS et IxJS évoluent vers une composition fonctionnelle sans point sur l'extension/l'héritage de prototype, cela permet une meilleure gestion des arborescences et une meilleure prise en charge des opérateurs personnalisés.

@felixfbecker Vous voulez dire les pipe ramda ? Je dois réessayer mais historiquement, ramda étant une bibliothèque JS-first, c'est très dynamique et difficile à taper (comme lodash), aggravé par le fait que TS avait beaucoup de mal à déduire des valeurs de retour de fonction (cela peut avoir été corrigé récemment, mais pas sûr)
Je n'utilise pas lodash car il est mal conçu, mélangeant des fonctions mutables et immuables dans un seul grand espace de noms.

Cela fonctionne en fait assez bien si vos fonctions et chaînes ne sont pas super folles :

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

Cela fonctionne en fait assez bien si vos fonctions et vos chaînes ne sont pas super folles

Permettez-moi de qualifier ici de « pas super fou » : les choses tombent en panne si vos fonctions ont des génériques (voir https://github.com/types/npm-ramda/issues/86), par exemple R.pipe(R.identity) .

De plus, soyons clairs, la proposition est l'étape 1. L'équipe de base devient encore plus timide pour introduire des choses avant l'étape 3. Les décorateurs font partie de l'exemple. Même s'ils étaient marqués comme _expérimentaux_, nous sommes tous allés de l'avant et avons activé ce drapeau et écrit tout notre code de production en les utilisant. La proposition a maintenant rebondi et il y a des changements fondamentaux dans la syntaxe et la sémantique qui vont signifier que nous allons tous devoir refactoriser notre code, ce qui place l'équipe de base dans une situation difficile, car s'ils prennent _seulement_ en charge la version finale syntaxe que tout le monde est cassé le jour où ils le publient, ou s'ils conservent les éléments hérités, d'autres changements dans le compilateur pourraient rendre difficile la prise en charge des deux syntaxes, et vous voudrez éventuellement vous débarrasser des anciens éléments, mais quand .. . 💥

Donc, la meilleure chose à faire avec des fonctionnalités basées sur des normes comme celle-ci, n'est pas de débattre du support ou du manque de support de TypeScript ici, c'est de vous trouver un représentant local sympathique du TC39 et de défendre que cette fonctionnalité est vraiment importante pour vous ainsi que de participer à la conversation de proposition liée ci-dessus sur GitHub. Plus vite la sémantique est résolue et plus vite on passe à l'étape 3, plus vite nous pourrons tous avoir de belles choses !

Maintenant que rxjs a des opérateurs lettables, ce serait une fonctionnalité encore plus géniale à avoir dans Typescript
https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md

Pouvons-nous avoir quelqu'un de l'équipe TS pour faire la lumière sur cette demande ?

L'ont, ils l'ont étiqueté ES Next et Suggestion ... Je peux vous citer le chapitre et vers d'autres endroits où ils ont commenté les propositions ES Next et quand et comment ils les mettent en œuvre ...

Un commentaire de leur part ne changera rien. Pensez-vous qu'ils travaillent secrètement dessus dans les coulisses, attendant de le faire jaillir sur la communauté ? Souvent, ils n'interviendront pas sur une question s'il n'y a rien à ajouter... Il n'y a rien à ajouter à ce qui a déjà été dit.

À ce stade, je pense qu'il serait très utile d'avoir des plugins qui étendent le langage. Ajouter des fonctionnalités qui ne feront pas partie du noyau du langage feraient partie de ces plugins.

@aminpaks je n'aime pas trop l'idée car elle pourrait rapidement mener à la babélification (comme dans la Tour de Babel pas l'excellent transpiler Babeljs 😀)

Étant donné que les plugins impliqueraient un comportement au niveau du type, il devient difficile de comprendre la signification des programmes et la gestion des dépendances au niveau de la source nécessiterait un certain nombre de fonctionnalités complexes mais très utiles qui font actuellement défaut à TypeScript.

Autant j'aimerais que cela soit partout possible, autant je suis heureux que TS adopte une approche plus réservée pour implémenter de nouvelles fonctionnalités et respecter les normes. Cette position rend TS plus attrayant dans l'ensemble pour les personnes comme moi qui se soucient profondément de s'écarter de la norme mais qui apprécient les fonctionnalités avancées fournies par la transpilation avant l'adoption du fournisseur de navigateur / du moteur JS (mais pas nécessairement avant la normalisation). C'est un équilibre délicat.

Personnellement, je ne suis pas en faveur de l'opérateur de pipeline au détriment de l'opérateur de liaison. C'est vraiment une question de lisibilité.

Donné:

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

opération de liaison :

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

opération de pipeline :

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

ts-team a raison de ne pas s'embêter jusqu'à l'étape 3; et même dans ce cas, les propositions de l'étape 3 peuvent toujours être retirées (par exemple SIMD). C'est dommage que nous ne puissions pas avoir de plugins - le "risque" est transféré au développeur individuel. Il existe également de nombreux autres cas d'utilisation pour les plugins, notamment pour prendre en charge des éléments tels que les fichiers .vue contenant du texte dactylographié.

@MeirionHughes Je suis d'accord. Bien que je préfère avoir l'opérateur de pipeline plutôt que pas de sucre du tout, il s'inspire des langages où les fonctions sont auto-curry et où les bibliothèques sont construites autour de l'exploitation de cela. Il suppose également que les méthodes de pipeline ne sont _pas_ membres des valeurs de pipeline.

Alors tu aurais

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

et puis tu écrirais

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

mais comme JavaScript n'exécute pas et ne peut pas exécuter de fonctions de curry automatique, il ne semble fonctionner correctement qu'avec des bibliothèques conçues pour le curry.

Je me trompe peut-être, je ne suis pas très au courant de la proposition.

Ensuite, une nouvelle bibliothèque qui fournit des fonctions util curry par défaut pourrait devenir le nouveau standard :p

@AlexGalays Je pense que c'est probable si cela passe. Tant que cela ne fait pas partie d'un complot subversif pour transformer JavaScript en OCaml, alors tout va bien.

@MeirionHughes, votre exemple n'est pas correct. Votre fonction where n'utilise pas du tout this , donc l'opérateur de liaison ne fonctionnerait pas. L'opérateur de liaison a également beaucoup de questions ouvertes pour la sécurité du type. Est-ce que where serait autorisé à accéder aux propriétés privées à partir de this comme une méthode de classe ? Sinon, quel est l'intérêt d'utiliser this ? Si oui, alors changer de propriété privée est soudainement un changement radical, qui va complètement à l'encontre de l'objectif des propriétés privées.
Vous indiquez également que la syntaxe est moins lisible, mais par exemple, omettez les parenthèses dans votre exemple d'opérateur de liaison mais ajoutez des parenthèses inutiles dans l'exemple de pipeline. Et l'opérateur de pipeline ne fonctionnera bien sûr pas du tout avec les fonctions écrites pour la liaison, mais il fonctionnera bien pour les fonctions curry, comme les opérateurs rxjs, ramda ou lodash/fp.

@aluanhaddad Outre toutes les bibliothèques fp, RxJS est un exemple de bibliothèque largement utilisée qui est passée d'opérateurs sur des prototypes (qui ont beaucoup de problèmes, principalement autour du tremblement d'arbre et de la sécurité des types génériques) aux opérateurs en tant que fonctions curry. La plupart des bibliothèques ne choisissent probablement pas cette voie pour le moment _parce que_ nous n'avons pas une bonne syntaxe pour cela.

@felixfbecker vous avez raison et l'exemple de @aluanhaddad qui

Quelqu'un a-t-il pensé ou implémente-t-il un transformateur personnalisé pour obtenir une prise en charge du pipeline un peu plus tôt ? À première vue, cela pourrait être fait via un transformateur personnalisé qui a simplement transpile babel _just_ la partie du pipeline elle-même. vous pouvez ensuite l'exécuter via : https://github.com/cevek/ttypescript

Est-ce une possibilité ? Utiliser des transformations personnalisées pour utiliser la syntaxe prise en charge par Babel, tout en maintenant le fonctionnement des outils TypeScripts ?

Peut-être? il existe un préréglage qui ne traite que les propositions 0-2 : https://www.npmjs.com/package/babel-preset-proposal-typescript - cela implique que vous le mettez avant de l'envoyer à dactylographié. Vous êtes intellisense sera probablement ennuyé cependant. Cependant, avec https://github.com/cevek/ttypescript#visual -studio-code, vous pourriez vous en tirer.

@MeirionHughes Je suis content que cela ait été utile ❤️.
Maintenant, nous avons juste besoin de #6606 pour pouvoir transformer des méthodes de prototypes arbitraires en fonctions curry !

TypeScript est une transformation babel maintenant, je pense qu'il devrait y avoir un moyen de séquencer dans le pipeline de désucrage avant le passage de TypeScript. Cependant, je n'ai aucune idée de la façon dont vous feriez fonctionner cela avec le serveur de langue.

J'ai ajouté une implémentation auto-hébergée pour TS #22816

En tant que l'une des personnes faisant pression pour l'opérateur de pipeline, je vous en supplie : veuillez ne _pas_ implémenter cela dans TypeScript jusqu'à ce qu'il soit avancé davantage. Nous discutons toujours de deux propositions potentielles, qui sont fondamentalement incompatibles l'une avec l'autre, donc TypeScript supplie un monde pénible s'il implémente cela trop tôt.

Si cette proposition vous intéresse, jetez un œil au repo ici et impliquez-vous : https://github.com/tc39/proposal-pipeline-operator/ Nous aimerions recevoir vos commentaires ! Et nous travaillons sur des plugins Babel pour les différentes propositions, vous aurez donc l'opportunité de les essayer dans vos projets (non TypeScript).

Mais la proposition n'est pas encore prête à atterrir dans quelque chose comme TypeScript.

Nous ne fusionnons certainement pas cela.

Pourrions-nous avoir quelque chose comme https://github.com/babel/babel-eslint , qui nous permet de continuer à utiliser les fonctionnalités prises en charge par Babel, et de faire en sorte que la vérification de type fonctionne après que les fonctionnalités non prises en charge par TypeScript aient été supprimées ?

@masaeedu Oui ! Cette

@MeirionHughes avec la proposition de candidature partielle, cela devient plus facile :

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

@bernatmv : fwiw il y a quelque chose de proche qui fonctionne aujourd'hui.

@tycho01 Mais pas dans TypeScript, pas avant qu'il n'obtienne 2,8 frappes : https://github.com/DefinitelyTyped/DefinitelyTyped/issues/25067

@jeremejevs @bernatmv en fait, R.__ a été tapé à l'aide de codegen dans npm-ramda . De meilleures façons d'utiliser la 2.8 bienvenue !

Je suis un peu novice en Javascript et TypeScript (2 semaines), alors veuillez m'excuser s'il existe une solution plus simple. Mais voici ce que j'ai trouvé en l'absence d'un exploitant de pipeline. J'ai à l'origine essayé d'avoir plusieurs surcharges de pipe qui fonctionnaient avec des paramètres de type 2, 3, 4, etc., mais je n'arrivais pas à comprendre comment faire en sorte que la résolution de surcharge TypeScript fonctionne comme en C#. Nous pourrions avoir différentes fonctions pipe1<A,B> , pipe2<A,B,C> , et pipe3<A,B,C,D> mais ce serait difficile à travailler car vous auriez à choisir le nom de la fonction en fonction du nombre d'arguments que vous voulait. Existe-t-il une solution de type sûr plus simple que celle que j'ai proposée ci-dessous ? Existe-t-il une définition de type récursif qui pourrait accepter un nombre illimité de paramètres ? Est-ce que j'utilise correctement les types de conditions ?

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

Je pensais que le _.flow de lodash/fp avait déjà tapé cela?

Le mercredi 9 mai 2018, 22:19 jmagaram, [email protected] a écrit :

Je suis un peu nouveau sur Javascript et TypeScript (2 semaines) alors veuillez pardonner
moi s'il existe une solution plus simple. Mais ci-dessous est ce que je suis venu
avec en l'absence d'un opérateur de pipeline. J'ai d'abord essayé d'avoir
plusieurs surcharges de tuyaux qui ont fonctionné avec le type 2, 3, 4, etc.
paramètres, mais je ne pouvais pas comprendre comment obtenir une surcharge TypeScript
résolution de fonctionner comme en C#. Nous pourrions avoir différentes fonctions
pipe1 , pipe2 et pipe3 mais ce serait difficile à travailler avec car vous devrez choisir le nom de la fonction en fonction du nombrearguments que vous vouliez.
Existe-t-il une définition de type récursif qui pourrait accepter unnombre illimité de paramètres ?

tapez LastOf = [B] s'étend [jamais] ?
B :[D] étend [jamais] ?
RÉ :[F] s'étend [jamais] ?

pipe de fonction ( un : un,carteA : (a : A) => B,mapB? : (b : B) => C,mapC? : (c : C) => D,mapD? : (d : D) => E,mapE? : (e : E) => F) : LastOf { const b = mapA(a);commutateur (mapB) {case non définie : renvoie b comme LastOf ; défaut: {const c = mapB(b);commutateur (mapC) {case non définie : renvoie c comme LastOf ; défaut: {const d = mapC(c);commutateur (mapD) {case non définie : renvoie d comme LastOf ; défaut: {const e = mapD(d);commutateur (mapE) {case non définie : renvoie e comme LastOf ;par défaut : renvoie mapE(e) en tant que LastOf ; }}}}}}}}

test("map une fois", () => {
résultat const = pipe(
2,
je => je * 10);
attendre(résultat).toBe(20);
});

test("carte deux fois", () => {
résultat const = pipe(
2,
je => je * 10,
i => the answer is ${i} );
expect(result).toBe('la réponse est 20');
});

test("carte trois fois", () => {
résultat const = pipe(
2,
je => je * 10,
je => -i,
i => ({ a : i, b : -i }));
expect(result).toEqual({ a: -20, b: 20 });
});

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-387878691 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAZQTLm6LrWe5KVx4aGBFUd4yRUHkkrZks5tw11cgaJpZM4OzVEg
.

Je viens de regarder lodash et vous avez raison - la fonction de flux accepte de nombreux paramètres et est fortement typée. Il ne semble pas que cela soit fait en pur TypeScript. Ils utilisent un fichier de définition de type pour toutes les surcharges. Je ne sais pas si c'est mieux ou pire que d'essayer de tout faire en TypeScript.

@jmagaram all TS facilite généralement les choses en raison de l'inférence, mais si cela fonctionne, cela fonctionne.

@jmagaram Une alternative dactylographiée pure un peu plus simple pourrait ressembler à ceci.

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

L'utilisation serait tout de même assez propre et fortement typée.

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

J'apprécierais vraiment la possibilité d'ajouter des opérateurs personnalisés. F# a une bonne approche pour cela.

En attendant, voici une approche plus simple sans emballage :

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

Cela donne:
ts-pipe-example
( pour plus d'informations, voir ici )

Cela dit, @graingert +1 tu as raison : lodash a déjà ça pour la composition (mais pas le tuyau) :

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

Alternativement, vous pouvez à la place ajouter un tube à Object.prototype :

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

Cela permet à la place :
capture
( pour plus d'informations, voir ici )

Espérons que cela aide d'autres!

Il a atterri dans Firefox sous le drapeau de compilation --enable-pipeline-operator .

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

Une minute de silence pour le héros déchu, l'opérateur de liaison :: , clôturé en faveur du mal |> 😢

Eh bien, je suppose que c'est dans l'œil du spectateur, car je préfère |> :D

salut au roi !

Et là j'ai pensé que c'était une chimère

Pipeline est essentiellement un cas d'utilisation simple de la monade d'identité. De plus, pipe est généralement compose à l'envers alors que pipeline ressemble plus à un pipe qui est invoqué tout de suite.

Quoi qu'il en soit, j'ai hâte de voir ça dans Typescript.

Bien qu'avoir un pipeline serait utile, je pense qu'il serait possible d'offrir la possibilité de définir des opérateurs personnalisés (fonctions dont le nom peut inclure des caractères spéciaux et dont le premier paramètre est à leur gauche) via un transformateur de compilateur. Quelqu'un est-il intéressé à essayer cela avec moi, ou a-t-il des connaissances à ce sujet ?

Le vendredi 10 août 2018, 02:53 Babak [email protected] a écrit :

Pipeline est essentiellement un cas d'utilisation simple de la monade d'identité. Aussi,
le tuyau est généralement composé à l'envers alors que le pipeline ressemble plus à un tuyau
qui est invoqué tout de suite.

Quoi qu'il en soit, j'ai hâte de voir ça dans Typescript.

-
Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411824741 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg
.

--

Infix fonctions ftw

Le jeu. 9 août 2018, 23:35 Ben Beattie-Hood, [email protected]
a écrit:

Bien qu'avoir un pipeline serait utile, je pense qu'il serait possible de
offrent la possibilité de définir des opérateurs personnalisés (fonctions dont le nom peut
comprennent des caractères spéciaux, et dont le premier paramètre est à leur gauche) via un
transformateur de compilateur. Toute personne intéressée à essayer cela avec moi, ou a
un peu d'arrière-plan à ce sujet ?

Le vendredi 10 août 2018, 02:53 Babak [email protected] a écrit :

Pipeline est essentiellement un cas d'utilisation simple de la monade d'identité. Aussi,
le tuyau est généralement composé à l'envers alors que le pipeline ressemble plus à un tuyau
qui est invoqué tout de suite.

Quoi qu'il en soit, j'ai hâte de voir ça dans Typescript.

-
Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail, consultez-le sur GitHub
<
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment -411824741
,
ou couper le fil
<
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg

.

--

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411919587 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AAZQTHHFbVY5uGCWl-La_P-HF7UN6xPsks5uPLk8gaJpZM4OzVEg
.

l'idée des fonctions infixes pour le tapuscrit est presque aussi ancienne que le tapuscrit : https://github.com/Microsoft/TypeScript/issues/2319

Je sais que beaucoup de gens veulent vraiment cela, mais je pense que TypeScript ne devrait pas implémenter d'opérateur supplémentaire tant qu'ils ne sont pas à l'étape 3. Les choses peuvent changer et bien sûr, il y a quelques exceptions.

Je pense que cela vaudrait la peine d'essayer en tant que transformateur de compilateur, juste pour permettre à la communauté d'explorer l'idée et de mesurer la popularité. C'est une fonctionnalité bien définie dans d'autres langages fonctionnels, il peut donc être assez sûr à explorer.

@BenBeattieHood Nous sommes en train de l'implémenter dans babel, vous pourrez donc le tester là-bas. Si vous le testez dans un transformateur de compilateur, jetez un coup d'œil aux propositions actuelles , car il existe quelques formes d'opérateur de pipeline que nous envisageons.

Je pense qu'il faudrait beaucoup de réflexion sur la façon dont il est utilisé; spécifiquement en ce qui concerne la saisie de choses comme :

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)

pour le moment avec where(x => x > 1)([1,2,3]) il ne peut pas déduire ce qu'est x. ce qui précède est l'une des raisons pour lesquelles j'espérais que l'opération :: l'emporterait, car il semble (à première vue) beaucoup plus facile pour le dactylographe de déduire ce qu'est this

Ou nous pouvons le voir d'une autre manière : s'il est publié, il donnera la priorité à certains des problèmes d'inférence que TS a 👍

Si vous suivez les actualités de la spécification et de babel, la spécification n'est pas encore définie. Il y a 2 propositions. Je suis sûr que l'équipe dactylographiée ajoutera un support lorsque la spécification sera finalisée

Infix fonctions ftw

iirc JS appelle ces "méthodes".

iirc JS appelle ces "méthodes"

@ tycho01 Votre commentaire est probablement

@BenBeattieHood Nous sommes en train de l'implémenter dans babel, vous pourrez donc le tester là-bas. Si vous le testez dans un transformateur de compilateur, jetez un œil aux propositions actuelles, car il existe quelques formes d'opérateur de pipeline que nous envisageons.

L'analyseur Babel prend désormais en charge la proposition de pipeline intelligent.

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

Les mises à jour?

Les mises à jour?

🤦‍♂️ TypeScript ne met en œuvre la proposition qu'après avoir atteint l'étape 3. L' opérateur du pipeline est actuellement à l'étape 1 et a de sérieux problèmes. Cette information a été fournie plusieurs fois dans ce fil.

un exemple de problèmes sérieux s'il vous plaît?

peut être...

⚠ Avertissement : Les détails de la syntaxe du pipeline sont actuellement instables. Deux propositions concurrentes sont à l'étude.

Oui, c'est ce que je considère comme un problème grave.

Je vais verrouiller celui-ci car tous les threads en attente du statut

Ping !

Cette page vous a été utile?
0 / 5 - 0 notes