如何在TypeScript 4中使用可变元组类型键入管道函数?
TypeScript 4发行说明的第二部分展示了如何使用可变元组类型来避免多个重载定义。我想应该可以为任意数量的参数键入这个如何在TypeScript 4中使用可变元组类型键入管道函数?,typescript,Typescript,TypeScript 4发行说明的第二部分展示了如何使用可变元组类型来避免多个重载定义。我想应该可以为任意数量的参数键入这个pipe函数 type F<P, R> = (p: P) => R type Pipe2<T1, T2, R> = [F<T1, T2>, F<T2, R>] type Pipe3<T1, T2, T3, R> = [F<T1, T2>, ...Pipe2<T2, T3, R>] t
pipe
函数
type F<P, R> = (p: P) => R
type Pipe2<T1, T2, R> = [F<T1, T2>, F<T2, R>]
type Pipe3<T1, T2, T3, R> = [F<T1, T2>, ...Pipe2<T2, T3, R>]
type Pipe4<T1, T2, T3, T4, R> = [F<T1, T2>, ...Pipe3<T2, T3, T4, R>]
function pipe<T1, R>(f1: F<T1, R>): F<T1, R>
function pipe<T1, T2, R>(...fns: Pipe2<T1, T2, R>): F<T1, R>
function pipe<T1, T2, T3, R>(...fns: Pipe3<T1, T2, T3, R>): F<T1, R>
function pipe<T1, T2, T3, T4, R>(...fns: Pipe4<T1, T2, T3, T4, R>): F<T1, R>
function pipe(...fns) {
return x => fns.reduce((res, f) => f(res), x)
}
在我展示我尝试过但不起作用的管道的签名之前,我展示了一些测试/示例及其预期行为
declare const a: any
const ae_pass_1: number = a as AssertReturn<number, number, number>
const ae_pass_2: string = a as AssertReturn<number, number, string>
// Expected compile error:
// Type 'string' does not satisfy the constraint 'number'.
// V
const ae_pass_3: string = a as AssertReturn<number, string, string>
// Expected compile error:
// Type 'string' is not assignable to type 'number'.
// V
const ae_fail_returnType: number = a as AssertReturn<number, number, string>
declare const pr1: PipeReturn<[F<number, string>]>
const pr1_pass: F<number, string> = pr1
// Expected compile error:
// Type 'F<number, string>' is not assignable to type 'F<number, boolean>'.
// V
const pr1_fail: F<number, boolean> = pr1
declare const pr2: PipeReturn<[F<number, string>, F<string, boolean>]>
const pr2_pass: F<number, boolean> = pr2
// Expected compile error:
// Type 'F<number, boolean>' is not assignable to type 'F<number, string>'.
// V
const pr2_fail: F<number, string> = pr2
declare const pa1: PipeArgs<[F<number, string>]>
const pa1_pass: [F<number, string>] = pa1
// Expected compile error:
// Type '[F<number, string>]' is not assignable to type '[F<number, boolean>]'.
// V
const pa1_fail: [F<number, boolean>] = pa1
declare const pa2: PipeArgs<[F<number, string>, F<string, boolean>]>
const pa2_pass: [F<number, string>, F<string, boolean>] = pa2
// Expected compile error:
// Type '[F<number, string>, F<string, boolean>]' is not assignable to type '[F<number, string>, F<number, boolean>]'.
// V
const pa2_fail: [F<number, string>, F<number, boolean>] = pa2
declare const numberToString: F<number, string>
declare const stringToBoolean: F<string, boolean>
// no compile error expected
const pipe_pass: F<number, boolean> =
pipe<[F<number, string>, F<string, boolean>]>(numberToString, stringToBoolean)
// no compile error expected
const pipe_pass_argTypeInfered: F<number, boolean> =
pipe(numberToString, stringToBoolean)
// assignment should cause compile error since second function should expect
// string as parameter, but actually expects number:
// Type 'F<number, boolean>' is not assignable to type 'F<number, string>'.
// V
const pipe_fail_returnType: F<number, string> =
pipe(numberToString, stringToBoolean)
// pipe call should cause compile error since second function should expect
// string as parameter, but actually expects number
// Expected compile error should be something like:
// Type 'F<number, string>' is not assignable to type 'F<string, T>'.
// V
const pipe_fail_args: F<number, string> = pipe(numberToString, numberToString)
修复以前的错误,但不会导致此预期错误
// pipe call should cause compile error since second function should expect
// string as parameter, but actually expects number
// Expected compile error should be something like:
// Type 'F<number, string>' is not assignable to type 'F<string, T>'.
// V
const pipe_fail_args: F<number, string> = pipe(numberToString, numberToString)
编辑2:顺便说一句,库必须键入最多10个参数(不是任意数量的参数)的pipe
函数
declare const a: any
const ae_pass_1: number = a as AssertReturn<number, number, number>
const ae_pass_2: string = a as AssertReturn<number, number, string>
// Expected compile error:
// Type 'string' does not satisfy the constraint 'number'.
// V
const ae_pass_3: string = a as AssertReturn<number, string, string>
// Expected compile error:
// Type 'string' is not assignable to type 'number'.
// V
const ae_fail_returnType: number = a as AssertReturn<number, number, string>
declare const pr1: PipeReturn<[F<number, string>]>
const pr1_pass: F<number, string> = pr1
// Expected compile error:
// Type 'F<number, string>' is not assignable to type 'F<number, boolean>'.
// V
const pr1_fail: F<number, boolean> = pr1
declare const pr2: PipeReturn<[F<number, string>, F<string, boolean>]>
const pr2_pass: F<number, boolean> = pr2
// Expected compile error:
// Type 'F<number, boolean>' is not assignable to type 'F<number, string>'.
// V
const pr2_fail: F<number, string> = pr2
declare const pa1: PipeArgs<[F<number, string>]>
const pa1_pass: [F<number, string>] = pa1
// Expected compile error:
// Type '[F<number, string>]' is not assignable to type '[F<number, boolean>]'.
// V
const pa1_fail: [F<number, boolean>] = pa1
declare const pa2: PipeArgs<[F<number, string>, F<string, boolean>]>
const pa2_pass: [F<number, string>, F<string, boolean>] = pa2
// Expected compile error:
// Type '[F<number, string>, F<string, boolean>]' is not assignable to type '[F<number, string>, F<number, boolean>]'.
// V
const pa2_fail: [F<number, string>, F<number, boolean>] = pa2
declare const numberToString: F<number, string>
declare const stringToBoolean: F<string, boolean>
// no compile error expected
const pipe_pass: F<number, boolean> =
pipe<[F<number, string>, F<string, boolean>]>(numberToString, stringToBoolean)
// no compile error expected
const pipe_pass_argTypeInfered: F<number, boolean> =
pipe(numberToString, stringToBoolean)
// assignment should cause compile error since second function should expect
// string as parameter, but actually expects number:
// Type 'F<number, boolean>' is not assignable to type 'F<number, string>'.
// V
const pipe_fail_returnType: F<number, string> =
pipe(numberToString, stringToBoolean)
// pipe call should cause compile error since second function should expect
// string as parameter, but actually expects number
// Expected compile error should be something like:
// Type 'F<number, string>' is not assignable to type 'F<string, T>'.
// V
const pipe_fail_args: F<number, string> = pipe(numberToString, numberToString)
function pipe<Fns extends F<any, any>[]>(...fns: PipeArgs<Fns>): PipeReturn<Fns>
const pipe_pass_argTypeInfered: F<number, boolean> =
// but
// Argument of type 'F<number, string>' is not assignable to parameter of type 'never'.(2345)
// The call would have succeeded against this implementation, but implementation signatures of overloads are not externally visible.
// V
pipe(numberToString, stringToBoolean)
function pipe<Fns extends F<any, any>[]>(...fns: Fns & PipeArgs<Fns>): PipeReturn<Fns>
// pipe call should cause compile error since second function should expect
// string as parameter, but actually expects number
// Expected compile error should be something like:
// Type 'F<number, string>' is not assignable to type 'F<string, T>'.
// V
const pipe_fail_args: F<number, string> = pipe(numberToString, numberToString)
// Type 'Fns' does not satisfy the constraint 'PipeArgs<Fns>'.
// Type 'F<any, any>[]' is not assignable to type 'PipeArgs<Fns>'.
// V
function pipe<Fns extends F<any, any>[]>(...fns: Fns): AssertReturn<PipeArgs<Fns>, Fns, PipeReturn<Fns>>