Typescript: 支持提议的 ES Next "|>" 管道操作符

创建于 2017-08-10  ·  79评论  ·  资料来源: microsoft/TypeScript

ES Next Suggestion Waiting for TC39

最有用的评论

现在处于第一阶段

所有79条评论

我最喜欢的建议 :( 如今,我们真的可以编写this免费程序。

供参考,TC39 提案: https :

并不是说该提案甚至还没有处于第 0 阶段。 如果它被添加到语言语义和其他细节可能会改变。

这将是我认为的第一个(除了一些像 Enum 和模块系统这样的老东西),但是实现这个的打字稿可以让它有更多的可见性,并在 ecma 生态系统的其他部分增加对它的需求吗?

只是想为受https://vanslaars.io/post/create-pipe-function/启发的失踪管道运营商分享一个解决方法

具有同步缩减的 SyncPipe

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

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

带异步缩减的管道(简化)

我大部分时间都使用这个:

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

我希望你会发现这很有帮助!

@PublicParadise样板文件太多:p

虽然我肯定希望在该语言中看到该运算符的一些变体,但对它的感知需求来自 ECMAScript 目前存在的两个不同限制。

第一个是很难用语言解决甚至解决的问题:无法以卫生的方式扩展内置对象。

然而,第二个根本不需要语言级别的支持,实际上可以纠正:标准库可以称为贫血。

最大最小是完全失败。

为什么要花费数月和数月的争论才能在语言中获得Array.prototype.flatMap

这是一种方法,它应该从一开始就存在,而且应该很明显应该添加它。

或许Array.prototype将在 6 年内有一个groupBy方法。

到目前为止,这已经有了一些 babel 实现,希望能对 TC39 提案有所帮助:

现在处于第一阶段

那么,这位美女有没有机会进入TS呢? 它将与 F# 一致。 <3

虽然有例外,但当提案对 TypeScript 和类型很重要时,提案通常要等到 TypeScript 的TC39 第 3 阶段才会实施,因为它们不够稳定,无法确保不会出现重大破坏和回归。

虽然目前还没有核心团队对此问题发表评论,但在我看来,这还不够重要,无法在第 3 阶段之前考虑实施。最好的重点是在 TC39 上支持冠军和提案。

如果只有 TS 可以选择仅通过管道传递此运算符以允许带有插件的 babel 处理它。
或者有自己的语法插件,比如 post-css。 等待一个原始运营商的几年实在是太多了。

@garkin :这里的挑战是 TS 需要了解代码来完成提供类型安全的工作,这与它不理解的随机代码不能很好地结合。 除非它要获取宏 (#4892),在这种情况下,它只会编译成它理解的代码。 但我不希望在路线图上做到这一点,因为标准库的相当多的部分仍然难以键入 atm。

现在 Babel 理解 typescript,你可以通过 Babel 运行它
打字稿

2017 年 10 月 26 日 19:01,“Tycho Grouwstra” [email protected]写道:

@garkin https://github.com/garkin :这里的挑战是 TS 需要
了解代码以完成其提供类型安全的工作,这并不
与它不理解的随机代码很好地结合起来。 除非它得到
宏(#4892 https://github.com/Microsoft/TypeScript/issues/4892 ),在
在这种情况下,它只会编译为它确实理解的代码。 但我不会
期望在路线图上,作为标准的相当多的位
图书馆仍然难以键入 atm。


您收到此消息是因为您编写了该主题。
直接回复此邮件,在 GitHub 上查看
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339748284
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAZQTO6UiVHbrM6SRwaBhm8obaa3R7e9ks5swMkCgaJpZM4OzVEg
.

现在 Babel 理解 typescript,你可以通过 Babel 运行它
打字稿

构建时间的两倍:p

如果 typescript 只是一个 Babel 插件那就太好了,那么你就不需要
通过这两个程序管道

2017 年 10 月 26 日 20:16,“AlexGalays” [email protected]写道:

现在 Babel 理解 typescript,你可以通过 Babel 运行它
打字稿

构建时间的两倍:p


您收到此消息是因为您编写了该主题。
直接回复此邮件,在 GitHub 上查看
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-339769856
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAZQTEArBw8jj0BcZFM2yLj5ErfbtNrgks5swNqagaJpZM4OzVEg
.

@graingert :这是一个不错的选择,我会对此进行调查。
不幸的是,它不适用于 VisualStudioCode、Webstorm 和其他 IDE 使用的 typescript Language Service API。

关于“TS 插件”,我们可以很容易地获得所需的结果,比方说,一个简单的(预)转译器​​用于管道运算符,它理解 TS 语法并产生与语句等效的强类型。 它可以通过类型检查和诸如此类的方式编译得很好。

它的 webpack 配置可能如下所示:

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

正如@garkin所指出的,唯一的挑战是 TS 服务无法将转译的部分与原始源文件相关联,然后使用该服务的 IDE 即使它们已经识别了操作符也无法正常工作(ES Next启用语法或其他东西)。

也许如果我们为 TS 服务创建一个 NFR(或者可能已经有一个?)以支持在源文件和提供给编译器的转译结果之间应用累积源映射,那么这个插件和其他插件将是可能的,而不会影响社区的其他人,最重要的是,不会增加核心团队处理的复杂性。


另外,我不知道#13940 与此有多少相关,但它显然是更复杂插件的良好开端。 但是在我看来,源映射方法仍然更简单,因为在大多数情况下,简约(预)转译器​​不需要项目上下文,因为从声明原始文本,然后以控制流能够暗示转译部分的特定 I/O 类型的方式重写它。


最后但并非最不重要的一点是,谁能指出我关于这种插件的_official_线程(如果有的话)?

我需要说我真的很欣赏引入新提案的冷静方式,并且更喜欢单体 Typescript 和 LessCSS 工具,而不是 Flow+Babel 和 Post-CSS 特殊插件 Olympics。

这是一种可定制性和在膨胀碎片和专业领域的成本中获得新功能的速度。

管道操作员就像进入功能世界的入门药物,它让我说和希望一些奇怪的事情。

因此,已经有 #14419 甚至一些有用的实际含义。 将那些与ts-loader整合起来应该不难。

tsconfig.json转换器集成(以及语言服务 API,而不仅仅是定制的tsc )#14654 被拒绝_在短期内_。

11976 正在讨论一个语言服务插件,它看起来像一个 linting only 工具。

16607 提议将这些插件扩展到变压器。

@PublicParadise还是只使用 lodash 的flow或 Rambda 的pipe

无论如何,看到 TS 支持这将是非常棒的。 我喜欢 JS 支持的功能模式(尤其是 TS 的类型推断),但有些模式读起来不太好。 这将是巨大的,因为像 RxJS 和 IxJS 这样的大型 TS 库正在朝着原型扩展/继承上的无点功能组合方向发展,它为更好的树摇动和对自定义运算符的支持提供了更好的方式。

@felixfbecker您的意思是ramda的pipe ? 我需要再试一次,但从历史上看,ramda 是一个 JS 优先的库,它非常动态且难以输入(如 lodash),再加上 TS 过去从函数返回值推断有很多麻烦(它可能是最近修复,但不确定)
我不使用lodash因为它设计得很糟糕,在一个大命名空间中混合了可变和不可变函数。

如果你的函数和链不是超级疯狂,它实际上工作得很好:

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

如果你的函数和链不是超级疯狂,它实际上工作得很好

让我在这里限定“不是超级疯狂”:如果您的函数具有泛型(请参阅 https://github.com/types/npm-ramda/issues/86),例如R.pipe(R.identity) ,事情就会崩溃。

另外,让我们明确一点,该提案是第 1 阶段。核心团队对于在第 3 阶段之前引入事物变得更加害羞。装饰器是示例的一部分。 即使它们被标记为_experimental_,我们都继续启用该标志并使用它们编写我们所有的生产代码。 该提案现在已经反弹,并且在语法和语义上有一些根本性的重大变化,这意味着我们都将不得不重构我们的代码,这使核心团队处于紧张的境地,因为如果他们_only_支持最终语法比每个人在发布之日都被破坏,或者如果他们保留遗留的东西,编译器中的其他更改可能会使支持这两种语法变得具有挑战性,最终你想摆脱旧的东西,但是当.. . 💥 💥

因此,使用此类基于标准的功能最好的办法不是在这里讨论 TypeScript 的支持或缺乏支持,而是找到友好的本地 TC39 代表并倡导此功能对您非常重要并参与其中在 GitHub 上链接到上面的提案对话。 语义解决得越快,进入第 3 阶段的速度越快,我们就能越快拥有美好的事物!

现在rxjs具有可出租的运算符,这将是 Typescript 中更棒的功能
https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md

我们可以请 TS 团队的人来解释一下这个请求吗?

有,他们已经标记了它ES NextSuggestion ...我可以引用你的章节和诗句,他们对 ES Next 提案以及他们何时以及如何实施它们发表了评论...

他们的评论不会改变任何事情。 您是否认为他们在幕后暗中工作,等待在社区中推广? 如果没有什么可补充的,他们通常不会就某个问题发表意见……对于已经说过的内容,没有什么可补充的。

在这一点上,我相信拥有扩展语言的插件会非常有用。 添加它们不会成为语言核心一部分的功能将成为这些插件的一部分。

@aminpaks我真的不喜欢这个想法,因为它可能很快导致 babelification(就像在巴别塔中而不是优秀的转译器 Babeljs 😀)

由于插件会暗示类型级别的行为,因此很难理解程序的含义,并且处理源级别的依赖项将需要 TypeScript 目前缺乏的许多复杂但非常有用的功能。

尽管我_喜欢_这在任何地方都是可能的,但我很高兴 TS 采取了更加保守的方法来实现新功能并坚持标准。 这种立场使 TS 对像我这样非常关心偏离标准但享受在浏览器供应商/JS 引擎采用之前提供的高级功能(但不一定在标准化之前)的人更具吸引力。 这是一个微妙的平衡行为。

就个人而言,我不赞成管道运营商以牺牲绑定运营商为代价。 这真的归结为可读性。

鉴于:

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

绑定操作:

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

管道操作:

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

ts-team 在第 3 阶段之前不打扰是对的; 即便如此,第 3 阶段的提案仍然可以撤回(例如 SIMD)。 遗憾的是我们不能拥有插件——“风险”被传递给了个人开发者。 插件还有很多其他用例,尤其是支持包含打字稿的.vue文件之类的东西。

@MeirionHughes我同意。 虽然我宁愿拥有管道运算符,也不愿完全没有糖,但它的灵感来自于函数自动柯里化的语言以及围绕利用它构建的库。 它还假设管道方法不是管道值的成员。

那么你会有

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

然后你会写

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

但是由于 JavaScript 没有也不能自动柯里化函数,它似乎只能与设计时考虑柯里化的库一起工作。

我可能弄错了,我对提案不是很了解。

然后一个默认提供 curried util 函数的新库可能会成为新标准:p

@AlexGalays我认为如果通过的话,这很可能。 只要它不是将 JavaScript 转换为 OCaml 的颠覆性阴谋的一部分,那么一切都很好。

@MeirionHughes你的例子不正确。 您的where函数根本不使用this ,因此绑定运算符不起作用。 绑定运算符也有很多关于类型安全的开放性问题。 将where允许访问私人性质this就像一个类的方法? 如果不是,那么使用this什么意义? 如果是的话,那么更改私有属性突然之间是一个严重的更改,这完全违背了私有属性的目的。
您还声明语法的可读性较低,但例如在绑定运算符示例中省略括号,但在管道示例中添加不需要的括号。 管道运算符当然不能与为绑定编写的函数一起使用,但它可以很好地用于 curried 函数,如 rxjs 运算符、ramda 或 lodash/fp。

@aluanhaddad除了所有 fp 库之外,RxJS 是一个广泛使用的库示例,它从原型上的运算符(有很多问题,主要是关于摇树和泛型类型安全)转移到作为柯里化函数的运算符。 大多数图书馆现在可能不会选择这种方式_因为_我们没有很好的语法。

@felixfbecker你是对的, @aluanhaddad的嵌套生成的函数的示例完全改变了我的想法。

有没有人考虑过或正在实施自定义转换器以更早地获得管道支持? 从它的外观上看,它可以通过一个自定义转换器来完成,该转换器简单地具有 babel transpile _just_ 管道部分本身。 然后您可以通过以下方式执行它: https :

有这种可能吗? 使用自定义转换来使用 Babel 支持的语法,同时保持 TypeScripts 工具之类的东西正常工作?

或许? 有一个仅处理 0-2 提案的预设: https : https://github.com/cevek/ttypescript#visual -studio-code 您可能会侥幸逃脱。

@MeirionHughes我很高兴这很有帮助❤️。
现在我们只需要 #6606 就可以将任意原型的方法转换为柯里化函数!

TypeScript 现在是一个 babel 转换,我认为应该有一种方法可以在 TypeScript 传递之前在管道中对脱糖进行排序。 不过,我不知道您如何使用语言服务器进行这项工作。

我为 TS #22816 添加了一个自托管的实现

作为推动管道运营商的人之一,我求你:请不要在 TypeScript 中实现它,直到它进一步发展。 我们仍在讨论两个潜在的提议,它们从根本上是不相容的,所以 TypeScript 祈求如果它太早实现这个世界会很痛苦。

如果您对此提案感兴趣,请查看此处的 repo 并参与其中: https :

但是该提案还没有准备好进入 TypeScript 之类的东西。

我们绝对不会合并这个。

我们能否有类似https://github.com/babel/babel-eslint 的东西,让我们继续使用 Babel 支持的功能,并在 TypeScript 不支持的功能被取消糖分后进行类型检查?

@masaeedu是的! 这

@MeirionHughes与部分申请提案变得更容易:

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

@bernatmv :fwiw 今天有一些接近它的东西。

@tycho01但不是在 TypeScript 中,直到它获得 2.8 个类型: https :

@jeremejevs @bernatmv实际上, R.__已使用npm-ramda 中的 codegen 输入。 欢迎使用 2.8 更好的方法!

我对 Javascript 和 TypeScript(2 周)有点陌生,所以如果有更简单的解决方案,请原谅我。但下面是我在没有管道操作员的情况下提出的。我最初尝试使用 2、3、4 等类型参数的多个pipe重载,但无法弄清楚如何让 TypeScript 重载解析像在 C# 中那样工作。我们可以有不同的函数pipe1<A,B>pipe2<A,B,C>pipe3<A,B,C,D>但这很难使用,因为你必须根据你有多少参数来选择函数名通缉。有没有比我在下面提出的更简单的类型安全解决方案?是否有可以接受无限数量参数的递归类型定义?我是否正确使用条件类型?

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

我以为 lodash/fp 的 _.flow 已经输入了这个?

2018 年 5 月 9 日星期三 22:19 jmagaram, notifications @github.com 写道:

我对 Javascript 和 TypeScript 有点陌生(2 周),所以请原谅
我是否有更简单的解决方案。 但下面是我想出的
在没有管道运营商的情况下。 我最初尝试过
使用 2、3、4 等类型的管道的多次过载
参数,但无法弄清楚如何获得 TypeScript 重载
像在 C# 中一样工作的分辨率。 我们可以有不同的功能
pipe1 , pipe2和 pipe3但这很难使用,因为您必须根据有多少选择函数名称你想要的论点。
是否有可以接受的递归类型定义无限数量的参数?

类型 LastOf = [B] 扩展 [从不] ?
乙:[D] 扩展 [从不] ?
丁:[F] 扩展 [从不] ?

功能管( 一个:一个,地图A:(a:A)=> B,mapB?: (b: B) => C,mapC?: (c: C) => D,mapD?: (d: D) => E,mapE?: (e: E) => F): LastOf { 常量 b = mapA(a);开关(地图B){未定义的情况:将 b 作为 LastOf 返回 默认: {常量 c = mapB(b);开关(地图C){情况未定义:将 c 作为 LastOf 返回 默认: {常量 d = mapC(c);开关 (mapD) {未定义的情况:将 d 作为 LastOf 返回 默认: {常量 e = mapD(d);开关(mapE){未定义的情况:将 e 作为 LastOf 返回默认值:返回 mapE(e) 作为 LastOf }}}}}}}}

test("映射一次", () => {
常量结果 = 管道(
2、
我 => 我 * 10);
期望(结果).toBe(20);
});

test("映射两次", () => {
常量结果 = 管道(
2、
我 => 我 * 10,
我 => the answer is ${i} );
expect(result).toBe('答案是 20');
});

test("映射三次", () => {
常量结果 = 管道(
2、
我 => 我 * 10,
我 => -我,
i => ({ a: i, b: -i }));
期望(结果).toEqual({ a: -20, b: 20 });
});


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-387878691
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAZQTLm6LrWe5KVx4aGBFUd4yRUHkkrZks5tw11cgaJpZM4OzVEg
.

我刚刚看了 lodash,你是对的 - 流函数接受许多参数并且是强类型的。 它看起来不像是用纯 TypeScript 完成的。 他们为所有重载使用类型定义文件。 我不确定这是否比尝试在 TypeScript 中完成所有操作更好或更差。

@jmagaram所有的 TS 通常由于推理而变得更容易,但如果它有效,它就可以工作。

@jmagaram一个更简单的纯打字稿替代品可能看起来像这样。

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

用法仍然相当干净和强类型。

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

我真的很感激能够添加自定义运算符。 F# 对此有一个很好的方法。

与此同时,这里有一个更简单的方法,没有包装:

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

这给出了:
ts-pipe-example
有关更多信息,请参见此处

就是说, @graingert +1 你是对的:lodash 已经有了这个组合(但不是管道):

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

或者,您可以改为将管道添加到 Object.prototype:

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

这允许:
capture
有关更多信息,请参见此处

希望这对其他人有帮助!

它已在--enable-pipeline-operator编译标志下登陆 Firefox。

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

为堕落的英雄,绑定运算符::默哀一分钟,为邪恶的|>关闭了😢

好吧,我想这是旁观者的看法,因为我更喜欢|> :D

向国王欢呼!

在这里,我认为这是一个白日梦

Pipeline 本质上是 Identity Monad 的一个简单用例。 此外, pipe通常是反向的compose ,而pipeline更像是立即调用的pipe

无论如何,期待在 Typescript 中看到这一点。

尽管拥有管道会有所帮助,但我认为可以通过编译器转换器提供定义自定义运算符(名称可能包含特殊字符,并且其第一个参数在其左侧的函数)的能力。 有人有兴趣和我一起尝试,或者有这方面的背景吗?

2018 年 8 月 10 日星期五 02:53,Babak [email protected]写道:

Pipeline 本质上是 Identity Monad 的一个简单用例。 还,
管道通常是反向组合的,而管道更像是管道
立即调用。

无论如何,期待在 Typescript 中看到这一点。


您收到此消息是因为您发表了评论。
直接回复此邮件,在 GitHub 上查看
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411824741
或使线程静音
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg
.

--

中缀函数 ftw

2018 年 8 月 9 日星期四 23:35 Ben Beattie-Hood, notifications@ github.com
写道:

尽管拥有管道会有所帮助,但我觉得有可能
提供定义自定义运算符的能力(名称可能
包括特殊字符,其第一个参数在左侧)通过
编译器转换器。 任何有兴趣和我一起尝试的人,或者有
这方面的一些背景?

2018 年 8 月 10 日星期五 02:53,Babak [email protected]写道:

Pipeline 本质上是 Identity Monad 的一个简单用例。 还,
管道通常是反向组合的,而管道更像是管道
立即调用。

无论如何,期待在 Typescript 中看到这一点。


您收到此消息是因为您发表了评论。
直接回复此邮件,在 GitHub 上查看
<
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment -411824741
,
或使线程静音
<
https://github.com/notifications/unsubscribe-auth/AFXUx5rwM9wVrpAkHK2BNYkyy74HtWU5ks5uPGkNgaJpZM4OzVEg

.

--


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看
https://github.com/Microsoft/TypeScript/issues/17718#issuecomment-411919587
或使线程静音
https://github.com/notifications/unsubscribe-auth/AAZQTHHFbVY5uGCWl-La_P-HF7UN6xPsks5uPLk8gaJpZM4OzVEg
.

打字稿中缀函数的想法几乎和打字稿一样古老: https :

我知道很多人都非常想要这个,但我相信 TypeScript 不应该实现任何额外的运算符,只要它们不在第 3 阶段。事情可能会发生变化,当然也有一些例外。

我认为作为编译器转换器值得尝试,只是为了让社区探索这个想法,并衡量流行度。 这是其他函数式语言中定义明确的特性,因此探索起来可能非常安全。

@BenBeattieHood我们正在 babel 中实现这个,所以你可以在那里测试它。 如果您确实在编译器转换器中对其进行测试,请务必查看当前的建议,因为我们正在考虑几种形式的管道运算符。

我认为需要对它的使用方式进行大量思考; 特别是关于键入以下内容:

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)

目前where(x => x > 1)([1,2,3])它无法推断 x 是什么。 以上是我希望::操作能够胜出的一个原因,因为(乍一看)打字稿似乎更容易推断出this是什么

或者我们可以换个角度看:如果它发布,它会优先考虑 TS 的一些推理问题👍

如果您关注规范和 babel 新闻,规范尚未设置。 有2个提案。 我确信打字稿团队会在规范完成后添加支持

中缀函数 ftw

iirc JS 称这些“方法”。

iirc JS 称这些“方法”

@tycho01你的评论可能是在

@BenBeattieHood我们正在 babel 中实现这个,所以你可以在那里测试它。 如果您确实在编译器转换器中对其进行测试,请务必查看当前的提议,因为我们正在考虑几种形式的管道运算符。

Babel 解析器现在支持智能管道提案。

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

任何更新?

任何更新?

🤦‍♂️ TypeScript 直到第 3 阶段才实施提案。管道运营商目前处于第 1 阶段并且存在严重问题。 该信息已在此线程中多次提供。

请举一个严重问题的例子?

或许...

⚠ 警告:管道语法的细节目前尚未确定。 有两个相互竞争的提案正在考虑中。

是的,这是我认为的一个严重问题。

将锁定这个,因为等待 TC39状态的所有线程往往只是在循环中。

平!

此页面是否有帮助?
0 / 5 - 0 等级