pipe() 函数的打字稿类型
Typescript types for a pipe() function
考虑以下 TypeScript 代码:
type operator<T> = (input:T) => T
const pipe = <T>(...operators:operator<T>[]) => (input:T):T => operators.reduce((output, f) => f(output), input)
const add2:operator<number> = x => x+2
const times3:operator<number> = x => x*3
console.log(pipe(add2, times3)(1)) //output 9
管道函数只是将一个运算符的输入通过管道传输到下一个运算符的结果。
现在考虑运算符类型的这个新定义:
type operator<T, U> = (input:T) => U
应该如何重写管道函数以便IDE让我知道我是否正确使用了类型?
例如:考虑这两个运算符:
const times3:operator<number, number> = x => x*3
const toStr:operator<number, string> = x => `${x}`
我希望它能正常工作:
pipe(times3, toStr)(1)
这里我希望 IDE 警告我类型错误:
pipe(toStr, times3)(1)
我想不通,先谢谢了。
这里是 RxJS does it:
pipe(): Observable<T>;
pipe<A>(op1: OperatorFunction<T, A>): Observable<A>;
pipe<A, B>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>): Observable<B>;
pipe<A, B, C>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>): Observable<C>;
pipe<A, B, C, D>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>
): Observable<D>;
pipe<A, B, C, D, E>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>
): Observable<E>;
pipe<A, B, C, D, E, F>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>
): Observable<F>;
pipe<A, B, C, D, E, F, G>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>,
op7: OperatorFunction<F, G>
): Observable<G>;
pipe<A, B, C, D, E, F, G, H>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>,
op7: OperatorFunction<F, G>,
op8: OperatorFunction<G, H>
): Observable<H>;
pipe<A, B, C, D, E, F, G, H, I>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>,
op7: OperatorFunction<F, G>,
op8: OperatorFunction<G, H>,
op9: OperatorFunction<H, I>
): Observable<I>;
pipe<A, B, C, D, E, F, G, H, I>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>,
op7: OperatorFunction<F, G>,
op8: OperatorFunction<G, H>,
op9: OperatorFunction<H, I>,
...operations: OperatorFunction<any, any>[]
): Observable<unknown>;
它不漂亮,但它完成了工作。
我知道它不是完全相同的函数签名,但是...我可以建议使用构建器模式吗?
const pipe = <A, B>(fn: (a: A) => B) => {
return {
f: function<C>(g: (x: B) => C) { return pipe((arg: A) => g(fn(arg)))},
build: () => fn
}
}
const compose = <A, B>(fn: (a: A) => B) => {
return {
f: function<C>(g: (x: C) => A) { return compose((arg: C) => fn(g(arg)))},
build: () => fn
}
}
const add = (x: number) => (y: number) => x + y
const format = (n: number) => `value: ${n.toString()}`
const upper = (s: string) => s.toUpperCase()
const process = pipe(add(2))
.f(add(6))
.f(format)
.f(upper)
.build()
const process2 = compose(upper)
.f(format)
.f(add(6))
.f(add(5))
.build()
console.log(process(6))
console.log(process2(6))
考虑以下 TypeScript 代码:
type operator<T> = (input:T) => T
const pipe = <T>(...operators:operator<T>[]) => (input:T):T => operators.reduce((output, f) => f(output), input)
const add2:operator<number> = x => x+2
const times3:operator<number> = x => x*3
console.log(pipe(add2, times3)(1)) //output 9
管道函数只是将一个运算符的输入通过管道传输到下一个运算符的结果。
现在考虑运算符类型的这个新定义:
type operator<T, U> = (input:T) => U
应该如何重写管道函数以便IDE让我知道我是否正确使用了类型?
例如:考虑这两个运算符:
const times3:operator<number, number> = x => x*3
const toStr:operator<number, string> = x => `${x}`
我希望它能正常工作:
pipe(times3, toStr)(1)
这里我希望 IDE 警告我类型错误:
pipe(toStr, times3)(1)
我想不通,先谢谢了。
这里是 RxJS does it:
pipe(): Observable<T>;
pipe<A>(op1: OperatorFunction<T, A>): Observable<A>;
pipe<A, B>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>): Observable<B>;
pipe<A, B, C>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>): Observable<C>;
pipe<A, B, C, D>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>
): Observable<D>;
pipe<A, B, C, D, E>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>
): Observable<E>;
pipe<A, B, C, D, E, F>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>
): Observable<F>;
pipe<A, B, C, D, E, F, G>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>,
op7: OperatorFunction<F, G>
): Observable<G>;
pipe<A, B, C, D, E, F, G, H>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>,
op7: OperatorFunction<F, G>,
op8: OperatorFunction<G, H>
): Observable<H>;
pipe<A, B, C, D, E, F, G, H, I>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>,
op7: OperatorFunction<F, G>,
op8: OperatorFunction<G, H>,
op9: OperatorFunction<H, I>
): Observable<I>;
pipe<A, B, C, D, E, F, G, H, I>(
op1: OperatorFunction<T, A>,
op2: OperatorFunction<A, B>,
op3: OperatorFunction<B, C>,
op4: OperatorFunction<C, D>,
op5: OperatorFunction<D, E>,
op6: OperatorFunction<E, F>,
op7: OperatorFunction<F, G>,
op8: OperatorFunction<G, H>,
op9: OperatorFunction<H, I>,
...operations: OperatorFunction<any, any>[]
): Observable<unknown>;
它不漂亮,但它完成了工作。
我知道它不是完全相同的函数签名,但是...我可以建议使用构建器模式吗?
const pipe = <A, B>(fn: (a: A) => B) => {
return {
f: function<C>(g: (x: B) => C) { return pipe((arg: A) => g(fn(arg)))},
build: () => fn
}
}
const compose = <A, B>(fn: (a: A) => B) => {
return {
f: function<C>(g: (x: C) => A) { return compose((arg: C) => fn(g(arg)))},
build: () => fn
}
}
const add = (x: number) => (y: number) => x + y
const format = (n: number) => `value: ${n.toString()}`
const upper = (s: string) => s.toUpperCase()
const process = pipe(add(2))
.f(add(6))
.f(format)
.f(upper)
.build()
const process2 = compose(upper)
.f(format)
.f(add(6))
.f(add(5))
.build()
console.log(process(6))
console.log(process2(6))