gpt4 book ai didi

typescript - 如何在 typescript 中键入管道函数?

转载 作者:行者123 更新时间:2023-12-04 11:55:59 30 4
gpt4 key购买 nike

这是普通 ol' js 中的管道函数:

const pipe = (f, ...fs) => x =>
f === undefined ? x : pipe(...fs)(f(x))

const foo = pipe(
x => x + 1,
x => `hey look ${x * 2} a string!`,
x => x.substr(0, x.length) + Array(5).join(x.substring(x.length - 1)),
console.log
)

foo(3) // hey look 8 a string!!!!!


(taken from this answer)

我如何用类型在 typescript 中写同样的东西?

即,当我使用管道函数时,我可以从当前函数的最后一个函数的返回类型中获取类型信息

最佳答案

原始(仍然推荐)答案
遗憾的是,除非您准备定义 pipe,否则目前在 Typescript 中这是不可能的。对于您可能想要的每个长度,这似乎不太有趣。
但是你可以靠近!
此示例使用 Promise -灵感then链接函数,但如果需要,您可以重命名它。

// Alias because TS function types get tedious fast
type Fn<A, B> = (_: A) => B;

// Describe the shape of Pipe. We can't actually use `class` because while TS
// supports application syntax in types, it doesn't in object literals or classes.
interface Pipe<A, B> extends Fn<A, B> {
// More idiomatic in the land of FP where `pipe` has its origins would be
// `map` / `fmap`, but this feels more familiar to the average JS/TS-er.
then<C>(g: Fn<B, C>): Pipe<A, C>
}

// Builds the `id` function as a Pipe.
function pipe<A>(): Pipe<A, A> {
// Accept a function, and promise to augment it.
function _pipe<A, B>(f: Fn<A, B>): Pipe<A, B> {
// Take our function and start adding stuff.
return Object.assign(f, {
// Accept a function to tack on, also with augmentations.
then<C>(g: Fn<B, C>): Pipe<A, C> {
// Compose the functions!
return _pipe<A, C>(a => g(f(a)));
}
});
}
// Return an augmented `id`
return _pipe(a => a);
}

const foo = pipe<number>()
.then(x => x + 1)
.then(x => `hey look ${x * 2} a string!`)
.then(x => x.substr(0, x.length) + Array(5).join(x.substring(x.length - 1)))
.then(console.log);

foo(3); // "hey look 8 a string!!!!!"
Check it out on Typescript Playground
编辑:危险区域
下面是一个灵活大小定义的示例,它的容量有限,但对于大多数应用程序来说应该足够大,并且您始终可以遵循该模式来扩展它。我不建议使用它,因为它非常困惑,但我想我会把它放在一起是为了好玩并展示这个概念。
在幕后,它使用您的 JS 实现(以类型安全的方式实现它是可能的,但很费力),而在现实世界中,您可能只是将它放在一个 JS 文件中,将此签名更改为 declare function ,并删除实现。 TS 不会让您在没有提示的情况下在单个文件中执行此操作,因此我只是为示例手动连接了它。
注:
  • 为避免推理问题,您需要为链中的第一个函数或返回的函数注释参数类型。后者对我来说似乎更整洁,所以这就是我在示例中使用的
  • 我的条件类型为错误留下了一些空间。如果您在第一个和最后一个定义的参数之间提供任何未定义的参数,我断言的类型可能不正确。不过应该可以解决这个问题,我现在无法面对它😉

  •     type Fn<A, B> = (_: A) => B;
    const Marker: unique symbol = Symbol();
    type Z = typeof Marker;

    function pipe<
    A,
    B,
    C = Z,
    D = Z,
    E = Z,
    F = Z,
    G = Z,
    H = Z,
    I = Z,
    J = Z,
    K = Z
    >(
    f: Fn<A, B>,
    g?: Fn<B, C>,
    h?: Fn<C, D>,
    i?: Fn<D, E>,
    j?: Fn<E, F>,
    k?: Fn<F, G>,
    l?: Fn<G, H>,
    m?: Fn<H, I>,
    n?: Fn<I, J>,
    o?: Fn<J, K>
    ): Fn<
    A,
    K extends Z
    ? J extends Z
    ? I extends Z
    ? H extends Z
    ? G extends Z
    ? F extends Z
    ? E extends Z
    ? D extends Z
    ? C extends Z
    ? B
    : C
    : D
    : E
    : F
    : G
    : H
    : I
    : J
    : K
    > {
    // @ts-ignore
    const pipe = (f, ...fs) => x => f === undefined ? x : pipe(...fs)(f(x));
    return pipe(f, g, h, i, j, k, l, m, n, o);
    }

    // Typechecks fine.
    const foo: Fn<number, void> = pipe(
    x => x + 1,
    x => `hey look ${x * 2} a string!`,
    x => x.substr(0, x.length) + Array(5).join(x.substring(x.length - 1)),
    console.log
    )

    foo(3) // hey look 8 a string!!!!!

    // Typechecks fine with fewer params.
    const bar: Fn<string, Date> = pipe(
    x => x + 1,
    _ => new Date()
    );
    console.log(bar("This string is ignored, but we'll put a date in console."));
    Check out this monstrosity on TS Playground

    关于typescript - 如何在 typescript 中键入管道函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44330774/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com