Typescript: Soporte propuesto ES Siguiente operador de canalización "|>"

Creado en 10 ago. 2017  ·  79Comentarios  ·  Fuente: microsoft/TypeScript

ES Next Suggestion Waiting for TC39

Comentario más útil

Está en la etapa 1 ahora

Todos 79 comentarios

Mi propuesta favorita :( Hoy en día, realmente podemos escribir this programas gratuitos.

Como referencia, la propuesta TC39: https://github.com/tc39/proposal-pipeline-operator

No es que la propuesta ni siquiera esté en la etapa 0 todavía. Si alguna vez se agrega al idioma, la semántica y otros detalles probablemente cambiarán.

Creo que sería la primera vez (además de algunos viejos como Enum y el sistema de módulos), pero ¿mecanografiar la implementación de esto podría darle más visibilidad y aumentar la demanda en el resto del ecosistema ecma?

Solo quería compartir una solución para el operador de tubería faltante inspirado en https://vanslaars.io/post/create-pipe-function/...

SyncPipe con reducción síncrona

// 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 con reducción asíncrona

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

Tubería con reducción asíncrona (simplificado)

Yo uso este la mayor parte del tiempo:

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

¡Espero que encuentre esto útil!

@PublicParadise demasiado repetitivo :p

Si bien definitivamente me gustaría ver alguna variante de este operador en el lenguaje, la necesidad percibida proviene de dos limitaciones diferentes de ECMAScript en su estado actual.

El primero es muy difícil de solucionar o incluso abordar en el idioma: la incapacidad de extender los objetos incorporados de manera higiénica.

El segundo, sin embargo, no necesita soporte de nivel de idioma en absoluto y, de hecho, podría rectificarse: la biblioteca estándar puede llamarse amablemente anémica.

Maximally Minimal es un completo fracaso.

¿Por qué lleva meses y meses de discusión obtener Array.prototype.flatMap en el idioma?

Ese es un método y debería haber estado allí desde el principio y debería ser obvio que debería agregarse.

Tal vez Array.prototype tendrá un método de groupBy en 6 años.

Por ahora, esto tiene algunas implementaciones de babel, que con suerte ayudarán a lo largo de la propuesta TC39:

Está en la etapa 1 ahora

Entonces, ¿alguna posibilidad de que esta belleza ingrese a TS? Estaría en línea con F#. <3

Si bien hay excepciones, cuando una propuesta es _importante_ para TypeScript y los tipos, la propuesta generalmente no se implementa hasta que alcanzan la etapa 3 de TC39 en TypeScript, ya que no son lo suficientemente estables para garantizar que no habrá interrupciones ni regresiones significativas.

Si bien ninguno de los miembros del equipo central ha comentado sobre este tema todavía, en mi opinión, no sería lo suficientemente importante como para considerar su implementación antes de la Etapa 3. El mejor enfoque es apoyar al campeón y la propuesta en TC39.

Si tan solo TS tuviera la opción de canalizar este operador para permitir que una babel con complementos se encargue de ello.
O tenía complementos de sintaxis propios, como post-css. Varios años esperando un operador primitivo es demasiado.

@garkin : el desafío aquí es que TS necesita comprender el código para hacer su trabajo de proporcionar seguridad de tipos, lo que no se combina bien con el código aleatorio que no comprende. A menos que fuera para obtener macros (#4892), en cuyo caso simplemente compilaría el código que entiende. Pero no esperaría eso en la hoja de ruta todavía, ya que algunos bits de la biblioteca estándar todavía son difíciles de escribir atm.

Ahora que Babel entiende mecanografiado, puede ejecutarlo a través de Babel y luego
mecanografiado

El 26 de octubre de 2017 a las 19:01, "Tycho Grouwstra" [email protected] escribió:

@garkin https://github.com/garkin : El desafío aquí es que TS necesita
entender el código para hacer su trabajo de proporcionar seguridad de tipo, que no
combinar bien con código aleatorio que no entiende. A menos que fuera para conseguir
macros (#4892 https://github.com/Microsoft/TypeScript/issues/4892 ), en
en cuyo caso simplemente compilaría el código que entiende. pero no lo haría
espere que en la hoja de ruta todavía, ya que algunos bits del estándar
biblioteca siguen siendo un reto para escribir atm.


Usted está recibiendo esto porque usted fue el autor del hilo.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339748284 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAZQTO6UiVHbrM6SRwaBhm8obaa3R7e9ks5swMkCgaJpZM4OzVEg
.

Ahora que Babel entiende mecanografiado, puede ejecutarlo a través de Babel y luego
mecanografiado

Sin embargo, el doble del tiempo de construcción: p

Sería bueno si mecanografiado fuera solo un complemento de Babel, entonces no necesitarías
tubería a través de ambos programas

El 26 de octubre de 2017 a las 20:16, "AlexGalays" [email protected] escribió:

Ahora que Babel entiende mecanografiado, puede ejecutarlo a través de Babel y luego
mecanografiado

Sin embargo, el doble del tiempo de construcción: p


Usted está recibiendo esto porque usted fue el autor del hilo.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339769856 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAZQTEArBw8jj0BcZFM2yLj5ErfbtNrgks5swNqagaJpZM4OzVEg
.

@graingert : es una buena opción, investigaré esto.
Desafortunadamente, no funcionará con la API de servicio de lenguaje mecanografiado que utilizan VisualStudioCode, Webstorm y otros IDE.

Con respecto a los "complementos de TS", uno podría lograr fácilmente el resultado deseado con, digamos, un (pre) transpilador simple para el operador de tubería que comprende la sintaxis de TS y produce su equivalente de tipo fuerte de la declaración. Se compilaría bien con verificación de tipos y demás.

Una configuración de paquete web para eso podría verse así:

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

El único desafío, como lo señaló @garkin , es que el servicio TS no podría correlacionar las partes transpiladas con el archivo fuente original, entonces los IDE que usan el servicio no funcionarían correctamente incluso si ya reconocen al operador (ES Next sintaxis habilitada o algo así).

Tal vez si creamos un NFR (¿o tal vez ya existe uno?) para que el servicio TS admita la aplicación de mapas de origen acumulativos entre el archivo de origen y el resultado transpilado que se alimenta al compilador, este y otros complementos serían posibles sin afectar el resto de la comunidad y, lo que es más importante, sin añadir más complejidad al equipo central.


Además, no puedo decir cuánto # 13940 está relacionado con esto, pero aparentemente es un buen comienzo hacia complementos más complejos. Sin embargo, me parece que el enfoque del mapa de origen sigue siendo una alternativa mucho más simple, ya que un (pre) transpilador minimalista no necesitaría el contexto del proyecto en la mayoría de los casos, ya que sería bastante fácil simplemente extraer los bloques de notación de tipo (si los hay) del texto sin procesar de la declaración y luego reescríbalo de manera que el flujo de control pueda implicar los tipos de E/S específicos para la parte transpilada.


Por último, pero no menos importante, ¿alguien podría señalarme el hilo _oficial_ (si corresponde) con respecto a este tipo de complementos?

Debo decir que realmente aprecio la forma tranquila de presentar nuevas propuestas y prefiero las herramientas monolíticas de Typescript y LessCSS mucho más que las olimpiadas de plugins especiales de Flow+Babel y Post-CSS.

Es una capacidad de personalización y una velocidad para obtener nuevas funciones a un costo de fragmentación inflada y un área de especialización.

El pipe operator es como una droga de entrada al mundo funcional, me hace decir y desear cosas raras.

Entonces, hay # 14419 e incluso algunas implicaciones prácticas útiles ya. No debería ser difícil integrar aquellos con ts-loader .

tsconfig.json integración de transformadores de tsc ) #14654 se rechazó _a corto plazo_.

11976 está discutiendo los complementos de Language Service, que parecen herramientas de solo pelusa.

16607 proponiendo la extensión de esos complementos a los transformadores.

@PublicParadise o simplemente usa flow lodash o pipe Rambda?

de todos modos, sería increíble ver que esto sea compatible con TS. Me encantan los patrones funcionales que admite JS (especialmente con la inferencia de tipos de TS), pero algunos patrones no se leen muy bien. Esto sería enorme, ya que las grandes bibliotecas de TS como RxJS e IxJS se están moviendo hacia una composición funcional sin puntos sobre la extensión/herencia de prototipos, lo que hace que la sacudida del árbol sea mucho mejor y el soporte para operadores personalizados.

@felixfbecker ¿ Te refieres a pipe ramda? Necesito volver a intentarlo, pero históricamente, ramda es una primera biblioteca de JS, es muy dinámica y difícil de escribir (como lodash), agravada por el hecho de que TS solía tener muchos problemas para inferir de los valores de retorno de la función (puede haber sido arreglado recientemente, pero no estoy seguro)
No uso lodash porque está mal diseñado, mezcla funciones mutables e inmutables en un gran espacio de nombres.

En realidad, funciona decentemente bien si sus funciones y cadenas no son súper locas:

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

En realidad, funciona decentemente bien si sus funciones y cadenas no son súper locas.

Permítanme calificar 'no súper loco' allí: las cosas se descomponen si sus funciones tienen genéricos (consulte https://github.com/types/npm-ramda/issues/86), por ejemplo, R.pipe(R.identity) .

Además, seamos claros, la propuesta es la Etapa 1. El equipo central se está volviendo aún más tímido para presentar cosas antes de la Etapa 3. Los decoradores son parte del ejemplo. A pesar de que estaban marcados como _experimental_, todos continuamos y habilitamos ese indicador y escribimos todo nuestro código de producción usándolos. La propuesta ahora ha rebotado y hay algunos cambios fundamentales en la sintaxis y la semántica que significarán que todos tendremos que refactorizar nuestro código, lo que pone al equipo central en una situación difícil, porque si _solo_ admiten la versión final sintaxis que todos están rotos el día que lo lanzan, o si mantienen las cosas heredadas, otros cambios en el compilador podrían dificultar el soporte de las dos sintaxis, y eventualmente querrás deshacerte de las cosas viejas, pero cuando... . 💥 💥

Entonces, lo mejor que se puede hacer con características basadas en estándares como esta, no es debatir el soporte de TypeScript o la falta de soporte aquí, es encontrar un representante local amigable de TC39 y recomendarle que esta característica es realmente importante para usted, así como participar en la conversación de la propuesta vinculada anteriormente en GitHub. ¡Cuanto más rápido se resuelva la semántica y más rápido llegue a la Etapa 3, más rápido podremos tener cosas buenas!

Ahora que rxjs tiene operadores letables, esta sería una característica aún más impresionante para tener en Typescript
https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md

¿Podemos pedirle a alguien del equipo de TS que arroje algo de luz sobre esta solicitud?

Lo han etiquetado como ES Next y Suggestion ... Puedo citar su capítulo y verso en otros lugares donde han comentado las propuestas de ES Next y cuándo y cómo las implementan...

Un comentario de ellos no cambiará nada. ¿Crees que están trabajando en secreto detrás de escena, esperando para revelarlo a la comunidad? A menudo no aportan información sobre un tema si no hay nada que agregar... No hay nada que agregar a lo que ya se ha dicho.

En este punto creo que sería muy útil tener complementos que amplíen el lenguaje. Agregar características que no van a ser parte del núcleo del lenguaje sería parte de estos complementos.

@aminpaks Realmente no me encanta la idea, ya que podría conducir rápidamente a la babelificación (como en la Torre de Babel, no el excelente traductor Babeljs 😀)

Dado que los complementos implicarían un comportamiento de nivel de tipo, se vuelve difícil comprender el significado de los programas y el manejo de las dependencias de nivel de fuente requeriría una serie de funciones complejas pero muy útiles de las que actualmente carece TypeScript.

Por mucho que me encantaría que esto estuviera en todos los lugares posibles, me alegra que TS esté adoptando un enfoque más reservado para implementar nuevas funciones y cumplir con los estándares. Esta postura hace que TS sea más atractivo en general para personas como yo, que se preocupan mucho por desviarse del estándar pero disfrutan de las funciones avanzadas que ofrece la transpilación antes de la adopción del proveedor del navegador/motor JS (pero no necesariamente antes de la estandarización). Es un delicado acto de equilibrio.

Personalmente, no estoy a favor del operador de tubería a expensas del operador de enlace. Todo se reduce a la legibilidad realmente.

Dado:

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

operación de enlace:

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

tubería-op:

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

ts-team tiene razón al no molestarse hasta la etapa 3; e incluso entonces las propuestas de la etapa 3 aún pueden retirarse (por ejemplo, SIMD). Sin embargo, es una pena que no podamos tener complementos: el "riesgo" se transfiere al desarrollador individual. También hay muchos otros casos de uso para complementos, sobre todo para admitir cosas como archivos .vue que contienen mecanografiado.

@MeirionHughes Estoy de acuerdo. Si bien preferiría tener el operador de tubería, que nada de azúcar, está inspirado en lenguajes donde las funciones se ejecutan automáticamente y donde las bibliotecas se construyen para aprovechar eso. También asume que los métodos de canalización _no_ son miembros de los valores de canalización.

Entonces tendrías

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

y luego escribirías

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

pero dado que JavaScript no hace y no puede ejecutar automáticamente funciones, solo parece funcionar bien con bibliotecas que están diseñadas teniendo en cuenta el curry.

Puede que me equivoque en esto, no estoy muy al día con la propuesta.

Entonces, una nueva biblioteca que proporcione funciones de utilidad curry por defecto podría convertirse en el nuevo estándar: p

@AlexGalays Creo que eso es probable si esto pasa. Mientras no sea parte de un complot subversivo para convertir JavaScript en OCaml, entonces todo está bien.

@MeirionHughes su ejemplo no es correcto. Su función where no usa this en absoluto, por lo que el operador de vinculación no funcionaría. El operador de enlace también tiene muchas preguntas abiertas sobre la seguridad de tipos. ¿Se le permitiría a where acceder a propiedades privadas desde this como un método de clase? Si no, ¿cuál es el punto de usar this ? Si es así, entonces cambiar las propiedades privadas es repentinamente un cambio radical, que anula por completo el propósito de las propiedades privadas.
También afirma que la sintaxis es menos legible, pero, por ejemplo, omite los paréntesis en su ejemplo de operador de enlace pero agrega paréntesis innecesarios en el ejemplo de canalización. Y el operador de tubería, por supuesto, no funcionará en absoluto con funciones escritas para enlace, pero funcionará bien para funciones curry, como operadores rxjs, ramda o lodash/fp.

@aluanhaddad Además de todas las bibliotecas fp, RxJS es un ejemplo de una biblioteca ampliamente utilizada que pasó de operadores en prototipos (que tienen muchos problemas, principalmente relacionados con el movimiento de árboles y la seguridad de tipos genéricos) a operadores como funciones curry. La mayoría de las bibliotecas probablemente no elijan esa forma en este momento _porque_ no tenemos una buena sintaxis para ello.

@felixfbecker tienes razón y el ejemplo de @aluanhaddad que anida las funciones resultantes que se canalizan me ha hecho cambiar de opinión por completo.

¿Alguien ha pensado o está implementando un transformador personalizado para obtener soporte de canalización un poco antes? Por lo que parece, podría hacerse a través de un transformador personalizado que simplemente hace que babel transpile _solo_ la parte de la tubería en sí. luego podría ejecutarlo a través de: https://github.com/cevek/ttypescript

¿Es esa una posibilidad? ¿Utiliza transformaciones personalizadas para usar la sintaxis compatible con Babel, mientras mantiene en funcionamiento cosas como las herramientas de TypeScripts?

¿Quizás? hay un ajuste preestablecido que solo se ocupa de las propuestas 0-2: https://www.npmjs.com/package/babel-preset-proposal-typescript - implica que lo ingresa antes de enviarlo a mecanografiado. Sin embargo, es probable que tu intellisense esté borracho. Sin embargo, con https://github.com/cevek/ttypescript#visual -studio-code puede salirse con la suya.

@MeirionHughes Me alegro de que haya sido útil ❤️.
¡Ahora solo necesitamos #6606 para que podamos transformar métodos de prototipos arbitrarios en funciones curry!

TypeScript es una transformación de babel ahora, creo que debería haber una forma de secuenciar en la canalización antes de que pase TypeScript. Sin embargo, no tengo idea de cómo harías que eso funcione con el servidor de idioma.

Agregué una implementación autohospedada para TS #22816

Como una de las personas que presiona por el operador de canalización, le ruego: _no_ implemente esto en TypeScript hasta que esté más avanzado. Todavía estamos debatiendo dos propuestas potenciales, que son fundamentalmente incompatibles entre sí, por lo que TypeScript está rogando por un dolor de cabeza si implementa esto demasiado pronto.

Si está interesado en esta propuesta, eche un vistazo al repositorio aquí y participe: https://github.com/tc39/proposal-pipeline-operator/ ¡ Nos encantaría recibir sus comentarios! Y estamos trabajando en complementos de Babel para las diferentes propuestas, por lo que tendrá la oportunidad de probarlos en sus proyectos (no TypeScript).

Pero la propuesta aún no está lista para aterrizar en algo como TypeScript.

Definitivamente no vamos a fusionar esto.

¿Podríamos tener algo como https://github.com/babel/babel-eslint , que nos permita continuar usando funciones compatibles con Babel y hacer que la verificación de tipos funcione después de que las funciones no compatibles con TypeScript se hayan eliminado?

@masaeedu ¡Sí! Esta

@MeirionHughes con la propuesta de aplicación parcial se vuelve más fácil:

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

@bernatmv: fwiw hay algo cerca de ella que funciona en la actualidad.

@ tycho01 Pero no en TypeScript, no hasta que obtenga 2.8 tipeos: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/25067

@jeremejevs @bernatmv en realidad, R.__ se ha escrito usando codegen en npm-ramda . ¡Mejores formas de usar 2.8, bienvenido!

Soy algo nuevo en Javascript y TypeScript (2 semanas), así que perdónenme si hay una solución más simple. Pero a continuación está lo que se me ocurrió en ausencia de un operador de tubería. Originalmente intenté tener múltiples sobrecargas de pipe que funcionaban con 2, 3, 4, etc. parámetros de tipo, pero no pude encontrar la manera de hacer que la resolución de sobrecarga de TypeScript funcionara como lo hace en C#. Podríamos tener diferentes funciones pipe1<A,B> , pipe2<A,B,C> y pipe3<A,B,C,D> pero sería difícil trabajar con esto ya que tendría que elegir el nombre de la función según la cantidad de argumentos que querido. ¿Existe una solución de tipo seguro más simple que la que propongo a continuación? ¿Existe una definición de tipo recursivo que pueda aceptar una cantidad ilimitada de parámetros? ¿Estoy utilizando correctamente los tipos de condiciones?

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

Pensé que _.flow de lodash/fp ya había escrito esto.

El miércoles 9 de mayo de 2018 a las 22:19 jmagaram, [email protected] escribió:

Soy un poco nuevo en Javascript y TypeScript (2 semanas), así que perdone
mí si hay una solución más simple por ahí. Pero a continuación es lo que he subido
en ausencia de un operador de tubería. Originalmente traté de tener
múltiples sobrecargas de tubería que trabajaba con tipo 2, 3, 4, etc.
parámetros, pero no pude averiguar cómo obtener la sobrecarga de TypeScript
resolución para que funcione como lo hace en C#. Podríamos tener diferentes funciones.
pipe1 , pipe2 y pipe3 pero esto sería difícil de trabajar ya que tendría que elegir el nombre de la función en función de cuántosargumentos que querías.
¿Existe una definición de tipo recursivo que podría aceptar unnúmero ilimitado de parámetros?

escriba LastOf = [B] se extiende [nunca] ?
B :[D] se extiende [nunca] ?
D :[F] se extiende [nunca] ?

tubería de función ( un: un,mapaA: (a: A) => B,mapaB?: (b: B) => C,mapaC?: (c: C) => D,mapD?: (d: D) => E,mapE?: (e: E) => F): LastOf { const b = mapA(a);cambiar (mapaB) {caso indefinido: devuelve b como LastOf ; defecto: {const c = mapB(b);cambiar (mapaC) {caso indefinido: devuelve c como LastOf ; defecto: {const d = mapC(c);cambiar (mapaD) {caso indefinido: devuelve d como LastOf ; defecto: {const e = mapD(d);cambiar (mapaE) {caso indefinido: devuelve e como LastOf ;predeterminado: devuelve mapE(e) como LastOf ; }}}}}}}}

test("mapa una vez", () => {
resultado const = tubería (
2,
yo => yo * 10);
esperar(resultado).toBe(20);
});

test("mapa dos veces", () => {
resultado const = tubería (
2,
yo => yo * 10,
yo => the answer is ${i} );
expect(resultado).toBe('la respuesta es 20');
});

test("mapa tres veces", () => {
resultado const = tubería (
2,
yo => yo * 10,
yo => -yo,
i => ({ a: i, b: -i }));
expect(resultado).toEqual({ a: -20, b: 20 });
});


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-387878691 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAZQTLm6LrWe5KVx4aGBFUd4yRUHkkrZks5tw11cgaJpZM4OzVEg
.

Acabo de mirar lodash y tiene razón: la función de flujo acepta muchos parámetros y está fuertemente tipada. No parece que esté hecho en TypeScript puro. Usan un archivo de definición de tipo para todas las sobrecargas. No estoy seguro de si esto es mejor o peor que intentar hacerlo todo en TypeScript.

@jmagaram all TS generalmente lo hace más fácil debido a la inferencia, pero si funciona, funciona.

@jmagaram Una alternativa mecanografiada pura algo más simple podría verse así.

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

El uso seguiría siendo bastante limpio y fuertemente tipado.

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

Realmente apreciaría la posibilidad de agregar operadores personalizados. F# tiene un buen enfoque para esto.

Mientras tanto, aquí hay un enfoque más simple sin el envoltorio:

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

Esto da:
ts-pipe-example
( para más información, ver aquí )

Dicho esto, @graingert +1 tienes razón: lodash ya tiene esto para la composición (pero no para la canalización):

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

Alternativamente, podría agregar una tubería al Object.prototype:

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

Esto permite en cambio:
capture
( para más información, ver aquí )

¡Espero que esto ayude a otros!

Ha aterrizado en Firefox bajo el indicador de compilación --enable-pipeline-operator .

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

Un minuto de silencio por el héroe caído, el operador de enlace :: , cerrado a favor del mal |> 😢

Bueno, supongo que está en el ojo del espectador, ya que prefiero |> :D

¡Viva el rey!

Y aquí pensé que era un sueño imposible

Pipeline es esencialmente un caso de uso simple de Identity Monad. Además, pipe suele ser compose al revés, mientras que pipeline es más como un pipe que se invoca de inmediato.

De todos modos, espero ver esto en Typescript.

Aunque tener una canalización sería útil, creo que sería posible ofrecer la capacidad de definir operadores personalizados (funciones cuyo nombre puede incluir caracteres especiales y cuyo primer parámetro está a la izquierda) a través de un transformador de compilación. ¿Alguien interesado en probar esto conmigo, o tiene algunos antecedentes sobre esto?

El viernes, 10 de agosto de 2018 a las 02:53, Babak [email protected] escribió:

Pipeline es esencialmente un caso de uso simple de Identity Monad. También,
la tubería generalmente se compone al revés, mientras que la tubería se parece más a una tubería
que se invoca de inmediato.

De todos modos, espero ver esto en Typescript.


Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411824741 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg
.

--

Funciones infijas ftw

El jueves, 9 de agosto de 2018, 23:35 Ben Beattie-Hood, [email protected]
escribió:

Aunque sería útil contar con una canalización, creo que sería posible
ofrecen la posibilidad de definir operadores personalizados (funciones cuyo nombre puede
incluyen caracteres especiales, y cuyo primer parámetro está a su izquierda) a través de un
transformador del compilador. Cualquier persona interesada en probar esto conmigo, o tiene
algunos antecedentes sobre esto?

El viernes, 10 de agosto de 2018 a las 02:53, Babak [email protected] escribió:

Pipeline es esencialmente un caso de uso simple de Identity Monad. También,
la tubería generalmente se compone al revés, mientras que la tubería se parece más a una tubería
que se invoca de inmediato.

De todos modos, espero ver esto en Typescript.


Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
<
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411824741
,
o silenciar el hilo
<
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg

.

--


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411919587 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAZQTHHFbVY5uGCWl-La_P-HF7UN6xPsks5uPLk8gaJpZM4OzVEg
.

la idea de funciones infijas para mecanografiado es casi tan antigua como mecanografiado: https://github.com/Microsoft/TypeScript/issues/2319

Sé que mucha gente quiere esto realmente, pero creo que TypeScript no debería implementar ningún operador adicional mientras no estén en la etapa 3. Las cosas pueden cambiar y, por supuesto, hay algunas excepciones.

Creo que valdría la pena intentarlo como un transformador de compilador, solo para permitir que la comunidad explore la idea y medir la popularidad. Es una característica bien definida en otros lenguajes funcionales, por lo que podría ser bastante seguro explorarla.

@BenBeattieHood Estamos en el proceso de implementar esto en babel, por lo que podrá probarlo allí. Si lo prueba en un transformador de compilación, definitivamente eche un vistazo a las propuestas actuales , ya que hay algunas formas del operador de tubería que estamos considerando.

Creo que necesitaría mucha reflexión sobre cómo se usa; específicamente con respecto a escribir cosas como:

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)

por el momento con where(x => x > 1)([1,2,3]) no se puede inferir que es x. lo anterior es una de las razones por las que esperaba que ganara la operación :: , porque (a primera vista) parece mucho más fácil para TypeScript inferir qué es this

O podemos verlo de otra manera: si se publica, priorizará algunos de los problemas de inferencia que tiene TS 👍

Si sigue las noticias de especificaciones y babel, las especificaciones aún no están establecidas. Hay 2 propuestas. Estoy seguro de que el equipo de mecanografiado agregará soporte cuando se finalice la especificación

Funciones infijas ftw

iirc JS llama a estos "métodos".

iirc JS llama a estos "métodos"

@ tycho01 Su comentario probablemente sea irónico, pero creo que no son exactamente lo mismo. No puede simplemente exportar una función binaria desde algún lugar y aplicarla infija a dos valores; el conocimiento sobre cada función que alguna vez manipulará el valor debe injertarse en el valor mismo, ya sea como una propiedad directa o en el prototipo. Esto es bastante inconveniente en escenarios prácticos.

@BenBeattieHood Estamos en el proceso de implementar esto en babel, por lo que podrá probarlo allí. Si lo prueba en un transformador compilador, definitivamente eche un vistazo a las propuestas actuales, ya que hay algunas formas del operador de canalización que estamos considerando.

El analizador de Babel ahora es compatible con la propuesta de canalización inteligente.

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

¿Alguna actualización?

¿Alguna actualización?

🤦‍♂️ TypeScript no implementa la propuesta hasta que llega a la Etapa 3. El operador de la canalización se encuentra actualmente en la Etapa 1 y tiene problemas graves. Esa información se ha proporcionado varias veces en este hilo.

un ejemplo de problemas serios por favor?

quizás...

⚠ Advertencia: los detalles de la sintaxis de la tubería no están resueltos actualmente. Hay dos propuestas en competencia bajo consideración.

Sí, eso es lo que considero un problema grave.

Voy a bloquear este ya que todos los subprocesos en el estado Esperando el TC39 tienden a ir en círculos.

¡Silbido!

¿Fue útil esta página
0 / 5 - 0 calificaciones