Tipando uma cadeia de funções

Como fazer sua função pipe ser fortemente tipada? Os conceitos por trás de tipos recursivos e cadeias de função

Contexto

Após a descoberta do reduce tipado, eu comecei a criar alguns desafios de tipo para poder ver até onde essa implementação resolve problemas do Typescript. Dessa vez me arrisquei a utilizar essa implementação para resolver o problema da função pipe.

tl;dr

Too long; didn't read

Caso você só queira somente olhar o resultado, você pode observar abaixo. Não se esqueça de instalar a dependência ts-toolbelt. Mas vale avisar que existe um limite para a tipagem desse modo, já que não é possível fazer uma extensa inferência. Isso é comentado nas implementações abaixo sobre o ramda e o lodash. Esse resultado é um resultado um pouco genérico e pode apresentar problemas em algumas implementações. Caso você queira uma solução um pouco mais robusta, você pode seguir com a leitura.

import { import LL, import NN } from "ts-toolbelt";
type type Fn = (a: any[]) => anyFn = (a: any[]a: any[]) => any;

type type Func = (...a: any[]) => anyFunc = (...a: any[]a: any[]) => any


type type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0> = Fns["length"] extends C ? Acc : PipeArgs<Fns, Fns[C], L.Merge<Acc, [(p: ReturnType<Func>) => ReturnType<Fns[C]>]>, N.Add<C, 1>>PipeArgs<function (type parameter) Fns in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Fns extends readonly type Fn = (a: any[]) => anyFn[], function (type parameter) Func in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Func extends type Fn = (a: any[]) => anyFn, function (type parameter) Acc in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Acc extends readonly type Fn = (a: any[]) => anyFn[] = [], function (type parameter) C in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>C extends number = 0> = function (type parameter) Fns in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Fns["length"] extends function (type parameter) C in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>C
    ? function (type parameter) Acc in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Acc
    : type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0> = Fns["length"] extends C ? Acc : PipeArgs<Fns, Fns[C], L.Merge<Acc, [(p: ReturnType<Func>) => ReturnType<Fns[C]>]>, N.Add<C, 1>>PipeArgs<function (type parameter) Fns in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Fns, function (type parameter) Fns in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Fns[function (type parameter) C in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>C], import LL.
type Merge<L extends List, L1 extends List, depth extends Depth = "flat", ignore extends object = BuiltIn, fill extends unknown = undefined> = Merge<L, L1, depth, ignore, fill> extends L.List ? Merge<L, L1, depth, ignore, fill> : L.List
export Merge
Accurately merge the fields of `L` with the ones of `L1`. It is equivalent to the spread operator in JavaScript. [[Union]]s and [[Optional]] fields will be handled gracefully. (⚠️ needs `--strictNullChecks` enabled)
@paramL to complete@paramL1 to copy from@paramdepth (?=`'flat'`) 'deep' to do it deeply@paramignore (?=`BuiltIn`) types not to merge@paramfill (?=`undefined`) types of `O` to be replaced with ones of `O1`@returns[[List]]@example```ts ```
Merge
<function (type parameter) Acc in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Acc, [(p: ReturnType<Func>p: type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<function (type parameter) Func in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Func>) => type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<function (type parameter) Fns in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>Fns[function (type parameter) C in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>C]>]>, import NN.
type Add<N1 extends number, N2 extends number> = N1 extends unknown ? N2 extends unknown ? _Add<IterationOf<N1>, IterationOf<N2>>[0] : never : never
export Add
Add a [[Number]] to another one
@paramN1 Left-hand side@paramN2 Right-hand side@returns`string | number | boolean`@example```ts import {N} from 'ts-toolbelt' type test0 = N.Add<'2', '10'> // '12' type test1 = N.Add<'0', '40'> // '40' type test2 = N.Add<'0', '40', 's'> // '40' type test3 = N.Add<'0', '40', 'n'> // 40 type test4 = N.Add<'-20', '40', 's'> // '20' type test5 = N.Add<'-20', '40', 'n'> // 20 ```
Add
<function (type parameter) C in type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0>C, 1>>;
type type PipeReturn<First extends Fn, Last extends Fn> = (...params: Parameters<First>) => ReturnType<Last>PipeReturn<function (type parameter) First in type PipeReturn<First extends Fn, Last extends Fn>First extends type Fn = (a: any[]) => anyFn, function (type parameter) Last in type PipeReturn<First extends Fn, Last extends Fn>Last extends type Fn = (a: any[]) => anyFn> = (...params: Parameters<First>params: type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
Obtain the parameters of a function type in a tuple
Parameters
<function (type parameter) First in type PipeReturn<First extends Fn, Last extends Fn>First>) => type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<function (type parameter) Last in type PipeReturn<First extends Fn, Last extends Fn>Last>;
export const const pipe: <A extends Func, T extends readonly Fn[]>(a: A, ...fns: PipeArgs<T, A>) => PipeReturn<A, L.Last<T>>pipe = <function (type parameter) A in <A extends Func, T extends readonly Fn[]>(a: A, ...fns: PipeArgs<T, A>): PipeReturn<A, L.Last<T>>A extends type Func = (...a: any[]) => anyFunc, function (type parameter) T in <A extends Func, T extends readonly Fn[]>(a: A, ...fns: PipeArgs<T, A>): PipeReturn<A, L.Last<T>>T extends readonly type Fn = (a: any[]) => anyFn[]>(a: A extends Funca: function (type parameter) A in <A extends Func, T extends readonly Fn[]>(a: A, ...fns: PipeArgs<T, A>): PipeReturn<A, L.Last<T>>A, ...fns: PipeArgs<T, A, [], 0>fns: type PipeArgs<Fns extends readonly Fn[], Func extends Fn, Acc extends readonly Fn[] = [], C extends number = 0> = Fns["length"] extends C ? Acc : PipeArgs<Fns, Fns[C], L.Merge<Acc, [(p: ReturnType<Func>) => ReturnType<Fns[C]>]>, N.Add<C, 1>>PipeArgs<function (type parameter) T in <A extends Func, T extends readonly Fn[]>(a: A, ...fns: PipeArgs<T, A>): PipeReturn<A, L.Last<T>>T, function (type parameter) A in <A extends Func, T extends readonly Fn[]>(a: A, ...fns: PipeArgs<T, A>): PipeReturn<A, L.Last<T>>A>): type PipeReturn<First extends Fn, Last extends Fn> = (...params: Parameters<First>) => ReturnType<Last>PipeReturn<function (type parameter) A in <A extends Func, T extends readonly Fn[]>(a: A, ...fns: PipeArgs<T, A>): PipeReturn<A, L.Last<T>>A, import LL.
type Last<L extends List> = L[L.Length<L.Tail<L>>]
export Last
Get the last entry of `L`
@paramL to extract from@returns[[Any]]@example```ts ```
Last
<function (type parameter) T in <A extends Func, T extends readonly Fn[]>(a: A, ...fns: PipeArgs<T, A>): PipeReturn<A, L.Last<T>>T>> =>
(fns: PipeArgs<T, A, [], 0>fns as type Fn = (a: any[]) => anyFn[]).Array<Fn>.reduce(callbackfn: (previousValue: Fn, currentValue: Fn, currentIndex: number, array: Fn[]) => Fn, initialValue: Fn): Fn (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@paramcallbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.@paraminitialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
reduce
(
(f: Fnf: type Fn = (a: any[]) => anyFn, g: Fng: type Fn = (a: any[]) => anyFn) => (args: anyargs: any) => g: (a: any[]) => anyg(f: (a: any[]) => anyf(args: anyargs)), (...args: unknown[]args: unknown[]) =>
a: A
(...a: any[]) => any
a
(...args: unknown[]args)) as any;

Pipe

Como dito no artigo de programação funcional, esse artigo visa explicar melhor a tipagem da função pipe e o porque dela ser tão complicada de tipar.

Antes de apresentar o código (que já está no tl;dr), vamos ver algumas implementações da função pipe

ramda

Ramda é uma biblioteca que busca trazer uma forma mais funcional para o Javascript, e depois para o Typescript. Olhando no repositório que contém os @types, podemos ver a seguinte implementação da função pipe do ramda. Caso você prefira, pode olhar a implementação direto no GitHub.

export function pipe<TArgs extends any[], R1, R2, R3, R4, R5, R6, R7, TResult>(
    ...funcs: [
        f1: (...args: TArgs) => R1,
        f2: (a: R1) => R2,
        f3: (a: R2) => R3,
        f4: (a: R3) => R4,
        f5: (a: R4) => R5,
        f6: (a: R5) => R6,
        f7: (a: R6) => R7,
        ...func: Array<(a: any) => any>,
        fnLast: (a: any) => TResult,
    ]
): (...args: TArgs) => TResult; // fallback overload if number of piped functions greater than 7
export function pipe<TArgs extends any[], R1, R2, R3, R4, R5, R6, R7>(
    f1: (...args: TArgs) => R1,
    f2: (a: R1) => R2,
    f3: (a: R2) => R3,
    f4: (a: R3) => R4,
    f5: (a: R4) => R5,
    f6: (a: R5) => R6,
    f7: (a: R6) => R7,
): (...args: TArgs) => R7;
export function pipe<TArgs extends any[], R1, R2, R3, R4, R5, R6>(
    f1: (...args: TArgs) => R1,
    f2: (a: R1) => R2,
    f3: (a: R2) => R3,
    f4: (a: R3) => R4,
    f5: (a: R4) => R5,
    f6: (a: R5) => R6,
): (...args: TArgs) => R6;
export function pipe<TArgs extends any[], R1, R2, R3, R4, R5>(
    f1: (...args: TArgs) => R1,
    f2: (a: R1) => R2,
    f3: (a: R2) => R3,
    f4: (a: R3) => R4,
    f5: (a: R4) => R5,
): (...args: TArgs) => R5;
export function pipe<TArgs extends any[], R1, R2, R3, R4>(
    f1: (...args: TArgs) => R1,
    f2: (a: R1) => R2,
    f3: (a: R2) => R3,
    f4: (a: R3) => R4,
): (...args: TArgs) => R4;
export function pipe<TArgs extends any[], R1, R2, R3>(
    f1: (...args: TArgs) => R1,
    f2: (a: R1) => R2,
    f3: (a: R2) => R3,
): (...args: TArgs) => R3;
export function pipe<TArgs extends any[], R1, R2>(
    f1: (...args: TArgs) => R1,
    f2: (a: R1) => R2,
): (...args: TArgs) => R2;
export function pipe<TArgs extends any[], R1>(f1: (...args: TArgs) => R1): (...args: TArgs) => R1;

É um pouco complicado de entender devido à sobrecarga de método utilizada no código. E é bem interessante lembrar disso porque outra biblioteca bastante famosa, o lodash também faz o uso da mesma técnica.

lodash

Como dito antes, aqui está o código do Lodash. E como podemos ver, ambos fazem o uso de sobrecarga de método para resolver o problema da função pipe.

interface LodashFlow {
    <A extends any[], R1, R2, R3, R4, R5, R6, R7>(f1: (...args: A) => R1, f2: (a: R1) => R2, f3: (a: R2) => R3, f4: (a: R3) => R4, f5: (a: R4) => R5, f6: (a: R5) => R6, f7: (a: R6) => R7): (...args: A) => R7;
    <A extends any[], R1, R2, R3, R4, R5, R6, R7>(f1: (...args: A) => R1, f2: (a: R1) => R2, f3: (a: R2) => R3, f4: (a: R3) => R4, f5: (a: R4) => R5, f6: (a: R5) => R6, f7: (a: R6) => R7, ...func: Array<lodash.Many<(a: any) => any>>): (...args: A) => any;
    <A extends any[], R1, R2, R3, R4, R5, R6>(f1: (...args: A) => R1, f2: (a: R1) => R2, f3: (a: R2) => R3, f4: (a: R3) => R4, f5: (a: R4) => R5, f6: (a: R5) => R6): (...args: A) => R6;
    <A extends any[], R1, R2, R3, R4, R5>(f1: (...args: A) => R1, f2: (a: R1) => R2, f3: (a: R2) => R3, f4: (a: R3) => R4, f5: (a: R4) => R5): (...args: A) => R5;
    <A extends any[], R1, R2, R3, R4>(f1: (...args: A) => R1, f2: (a: R1) => R2, f3: (a: R2) => R3, f4: (a: R3) => R4): (...args: A) => R4;
    <A extends any[], R1, R2, R3>(f1: (...args: A) => R1, f2: (a: R1) => R2, f3: (a: R2) => R3): (...args: A) => R3;
    <A extends any[], R1, R2>(f1: (...args: A) => R1, f2: (a: R1) => R2): (...args: A) => R2;
    (...func: Array<lodash.Many<(...args: any[]) => any>>): (...args: any[]) => any;
}

lodash vs ramda

Como você pode observer no código, o lodash e o ramda possuem um número finito de funções que podem ser encadeadas. Tudo bem que 7 funções para um pipe pode ser um exagero tremendo, mas caso você precise de extender isso ou apenas se desafiar a como resolver um problema de tipagem, você pode resolver utilizando os tipos recursivos + reduce.

Pipe tipado + Type Reduce

Antes de tudo, é válido lembrar que a inferência do pipe acaba não sendo extensa, devido à limitação na inferência no rest parameters.

Se você leu o artigo de type reduce, você terá um pouco mais de contexto de como funciona a lógica desse tipo. Infelizmente o Typescript não nos ajuda na inferência dos tipos através do rest-parameter, como dito anteriormente. Porém, para contornar esse problema nós vamos utilizar algumas artemanhas da linguagem para poder resolver esse problema.

Rest Parameter e o problema de inferência

Como nós visamos receber pelo menos duas funções, os primeiros dois argumentos precisam ser especificados. Do terceiro em diante nós vamos aceitar quaisquer funções, não importa se sejam 10 ou nenhuma.

O problema do rest parameter nesse caso é que precisamos aplicar uma regra nos parâmetros, sendo que eles não foram recebidos e tratados da forma devida da linguagem. Alterar os parâmetros da função diretamente no construtor da função acabam confundindo o nosso type system e jogando toda a inferência para o lado any da força.

Tendo isso em mente, ao invés de testar os parâmetros em sua entrada, por que nós não podemos modificar a saída em caso da entrada estar errada? Quê?????????????????????????????

Fica tranquilo, vamos entender um pouco melhor essa frase.

  1. Iremos receber 3 parâmetros na nossa função first, second e um rest, sendo esse um rest parameter (N funções permitidas). 1. O parâmetro first precisa extender (...params: any[]) => any. Pois, a entrada pode ter N argumentos. 2. Os parâmetros second e rest precisam extender (a: any) => any. Como todas as funções possuem somente um retorno, essas funções só podem ter uma entrada.
  2. Os parâmetros serão recebidos e entendidos pelo Typescript, sem precisar realizar nenhuma operação, com isso a inferência do tipo será preservada e nossas funções poderão ser devidamente tratadas
  3. O retorno da nossa função pipe será um retorno customizado baseado na entrada.
    1. Caso todas as funções respeitem a regra O tipo de entrada da função é o mesmo do retorno da função anterior, nós poderemos retornar a execução da função pipe de forma adequada
    2. Caso uma das funções não respeite a regra, iremos criar um objeto customizado e não permitir que pipe retorne uma função.
  4. Para criar o retorno, iremos criar os argumentos da nossa função pipe normalmente
  5. Após a criação, vamos comparar as entradas e saídas com as funções passadas
  6. Caso uma das funções tenha erro, iremos marca-lá como false e armazenar o seu index
  7. Todas as funções que possuirem erros serão armazenadas num acumulador para serem tratadas como erro
  8. Por fim, teremos um tipo que irá converter todas as funções erradas em objetos de erro
  9. A função pipe irá deixar de retornar uma função e irá retornar um objeto com os erros presentes nas funções

Code

A lógica pode ser um pouco complicada, mas que tal a gente ir comentando o código para facilitar o entendimento? Se você preferir, pode olhar o playground

// Utilitários para que possamos iterar os arrays
import { import FF, import NN } from "ts-toolbelt";

// funções que recebem somente um argumento
type type Unary = (a: any) => anyUnary = (a: anya: any) => any;

// funções que recebem N argumentos
type type Func = (...a: any[]) => anyFunc = (...a: any[]a: any[]) => any;

type type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0> = Fns["length"] extends I ? Acc : I extends 0 ? Pipe<Fns[I], Fns, [...Acc, (...params: Parameters<First>) => ReturnType<First>], N.Add<I, 1>> : Pipe<...>Pipe<
    // primeira função de referência pipe
    function (type parameter) First in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>First extends type Func = (...a: any[]) => anyFunc,
    // todas as funções passadas na nossa função pipe
    function (type parameter) Fns in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Fns extends interface Array<T>Array<type Func = (...a: any[]) => anyFunc | type Unary = (a: any) => anyUnary>, 
    // acumulador de argumentos
    function (type parameter) Acc in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Acc extends type Func = (...a: any[]) => anyFunc[] = [], 
    // contador do nosso tipo recursivo
    function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I extends number = 0
    // Aqui testamos a condição para saber se chegamos ao fim do array
> = function (type parameter) Fns in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Fns["length"] extends function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I
    // Caso o tamanho do array seja o mesmo do contador, retornamos o acumulador
  ? function (type parameter) Acc in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Acc
  : (
      // Nesse ponto testamos para saber se é a primeira função de pipe
    function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I extends 0 ?
        // Caso seja a primeira função, utilizamos os parâmetros recebidos por ela
    type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0> = Fns["length"] extends I ? Acc : I extends 0 ? Pipe<Fns[I], Fns, [...Acc, (...params: Parameters<First>) => ReturnType<First>], N.Add<I, 1>> : Pipe<...>Pipe<function (type parameter) Fns in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Fns[function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I], function (type parameter) Fns in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Fns, [...function (type parameter) Acc in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Acc, (...params: Parameters<First>params: type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
Obtain the parameters of a function type in a tuple
Parameters
<function (type parameter) First in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>First>) => type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<function (type parameter) First in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>First>], import NN.
type Add<N1 extends number, N2 extends number> = N1 extends unknown ? N2 extends unknown ? _Add<IterationOf<N1>, IterationOf<N2>>[0] : never : never
export Add
Add a [[Number]] to another one
@paramN1 Left-hand side@paramN2 Right-hand side@returns`string | number | boolean`@example```ts import {N} from 'ts-toolbelt' type test0 = N.Add<'2', '10'> // '12' type test1 = N.Add<'0', '40'> // '40' type test2 = N.Add<'0', '40', 's'> // '40' type test3 = N.Add<'0', '40', 'n'> // 40 type test4 = N.Add<'-20', '40', 's'> // '20' type test5 = N.Add<'-20', '40', 'n'> // 20 ```
Add
<function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I, 1>>
// Caso não seja, utilizamos o retorno da função anterior como parâmetro : type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0> = Fns["length"] extends I ? Acc : I extends 0 ? Pipe<Fns[I], Fns, [...Acc, (...params: Parameters<First>) => ReturnType<First>], N.Add<I, 1>> : Pipe<...>Pipe<function (type parameter) Fns in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Fns[function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I], function (type parameter) Fns in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Fns, [...function (type parameter) Acc in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Acc, (param: ReturnType<Fns[N.Sub<I, 1>]>param: type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<function (type parameter) Fns in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Fns[import NN.
type Sub<N1 extends number, N2 extends number> = N1 extends unknown ? N2 extends unknown ? _Sub<IterationOf<N1>, IterationOf<N2>>[0] : never : never
export Sub
Subtract a [[Number]] from another one
@paramN1 Left-hand side@paramN2 Right-hand side@returns`string | number | boolean`@example```ts import {N} from 'ts-toolbelt' type test0 = N.Sub<'2', '10'> // '-8' type test1 = N.Sub<'0', '40'> // '-40' type test2 = N.Sub<'0', '40', 's'> // '-40' type test3 = N.Sub<'0', '40', 'n'> // -40 type test4 = N.Sub<'-20', '40', 's'> // string type test5 = N.Sub<'-20', '40', 'n'> // number ```
Sub
<function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I, 1>]>) => type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<function (type parameter) Fns in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>Fns[function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I]>], import NN.
type Add<N1 extends number, N2 extends number> = N1 extends unknown ? N2 extends unknown ? _Add<IterationOf<N1>, IterationOf<N2>>[0] : never : never
export Add
Add a [[Number]] to another one
@paramN1 Left-hand side@paramN2 Right-hand side@returns`string | number | boolean`@example```ts import {N} from 'ts-toolbelt' type test0 = N.Add<'2', '10'> // '12' type test1 = N.Add<'0', '40'> // '40' type test2 = N.Add<'0', '40', 's'> // '40' type test3 = N.Add<'0', '40', 'n'> // 40 type test4 = N.Add<'-20', '40', 's'> // '20' type test5 = N.Add<'-20', '40', 'n'> // 20 ```
Add
<function (type parameter) I in type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0>I, 1>>
) type type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0> = Fns["length"] extends I ? Acc : ExtractInfo<Fns, Transform, [...Acc, Parameters<Fns[I]> extends Parameters<Transform[I]> ? unknown : Fns[I]], N.Add<...>>ExtractInfo< // Todas as funções originais function (type parameter) Fns in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Fns extends type Func = (...a: any[]) => anyFunc[], // Todas as funções transformadas function (type parameter) Transform in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Transform extends type Func = (...a: any[]) => anyFunc[], // acumulador de erros function (type parameter) Acc in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Acc extends any[] = [], // contador function (type parameter) I in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>I extends number = 0 // Fim da recursão > = function (type parameter) Fns in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Fns["length"] extends function (type parameter) I in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>I ? function (type parameter) Acc in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Acc // recursão : type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0> = Fns["length"] extends I ? Acc : ExtractInfo<Fns, Transform, [...Acc, Parameters<Fns[I]> extends Parameters<Transform[I]> ? unknown : Fns[I]], N.Add<...>>ExtractInfo<function (type parameter) Fns in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Fns, function (type parameter) Transform in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Transform, [ ...function (type parameter) Acc in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Acc, ( // Aqui é feito um teste para ver se os parâmetros // da função transformada são iguais aos da função // original. Caso sejam iguais, um unknown é retornado. // Caso sejam diferentes, retornamos a própria função type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
Obtain the parameters of a function type in a tuple
Parameters
<function (type parameter) Fns in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Fns[function (type parameter) I in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>I]> extends type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
Obtain the parameters of a function type in a tuple
Parameters
<function (type parameter) Transform in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Transform[function (type parameter) I in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>I]> ? unknown : function (type parameter) Fns in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>Fns[function (type parameter) I in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>I]
) ], import NN.
type Add<N1 extends number, N2 extends number> = N1 extends unknown ? N2 extends unknown ? _Add<IterationOf<N1>, IterationOf<N2>>[0] : never : never
export Add
Add a [[Number]] to another one
@paramN1 Left-hand side@paramN2 Right-hand side@returns`string | number | boolean`@example```ts import {N} from 'ts-toolbelt' type test0 = N.Add<'2', '10'> // '12' type test1 = N.Add<'0', '40'> // '40' type test2 = N.Add<'0', '40', 's'> // '40' type test3 = N.Add<'0', '40', 'n'> // 40 type test4 = N.Add<'-20', '40', 's'> // '20' type test5 = N.Add<'-20', '40', 'n'> // 20 ```
Add
<function (type parameter) I in type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0>I, 1>>
// Aqui é um tipo recursivo utilitário para identificar se algum item do array // é uma função. Ele irá nos ajudar a identificar os erros type type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0> = Result extends true ? true : Tests["length"] extends I ? false : OneIsFunction<Tests, Tests[I] extends Func ? true : false, N.Add<I, 1>>OneIsFunction<function (type parameter) Tests in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>Tests extends unknown[], function (type parameter) Result in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>Result extends boolean = false, function (type parameter) I in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>I extends number = 0> = function (type parameter) Result in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>Result extends true ? true : function (type parameter) Tests in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>Tests["length"] extends function (type parameter) I in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>I ? false : type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0> = Result extends true ? true : Tests["length"] extends I ? false : OneIsFunction<Tests, Tests[I] extends Func ? true : false, N.Add<I, 1>>OneIsFunction<function (type parameter) Tests in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>Tests, function (type parameter) Tests in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>Tests[function (type parameter) I in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>I] extends type Func = (...a: any[]) => anyFunc ? true : false, import NN.
type Add<N1 extends number, N2 extends number> = N1 extends unknown ? N2 extends unknown ? _Add<IterationOf<N1>, IterationOf<N2>>[0] : never : never
export Add
Add a [[Number]] to another one
@paramN1 Left-hand side@paramN2 Right-hand side@returns`string | number | boolean`@example```ts import {N} from 'ts-toolbelt' type test0 = N.Add<'2', '10'> // '12' type test1 = N.Add<'0', '40'> // '40' type test2 = N.Add<'0', '40', 's'> // '40' type test3 = N.Add<'0', '40', 'n'> // 40 type test4 = N.Add<'-20', '40', 's'> // '20' type test5 = N.Add<'-20', '40', 'n'> // 20 ```
Add
<function (type parameter) I in type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0>I, 1>>
// Aqui é um outro tipo recursivo que nos ajuda a identificar o index // da função com erro. type type FunctionIndexError<Tests extends unknown[], I extends number = 0> = Tests[I] extends Func ? I : FunctionIndexError<Tests, N.Add<I, 1>>FunctionIndexError<function (type parameter) Tests in type FunctionIndexError<Tests extends unknown[], I extends number = 0>Tests extends unknown[], function (type parameter) I in type FunctionIndexError<Tests extends unknown[], I extends number = 0>I extends number = 0> = function (type parameter) Tests in type FunctionIndexError<Tests extends unknown[], I extends number = 0>Tests[function (type parameter) I in type FunctionIndexError<Tests extends unknown[], I extends number = 0>I] extends type Func = (...a: any[]) => anyFunc ? function (type parameter) I in type FunctionIndexError<Tests extends unknown[], I extends number = 0>I : type FunctionIndexError<Tests extends unknown[], I extends number = 0> = Tests[I] extends Func ? I : FunctionIndexError<Tests, N.Add<I, 1>>FunctionIndexError<function (type parameter) Tests in type FunctionIndexError<Tests extends unknown[], I extends number = 0>Tests, import NN.
type Add<N1 extends number, N2 extends number> = N1 extends unknown ? N2 extends unknown ? _Add<IterationOf<N1>, IterationOf<N2>>[0] : never : never
export Add
Add a [[Number]] to another one
@paramN1 Left-hand side@paramN2 Right-hand side@returns`string | number | boolean`@example```ts import {N} from 'ts-toolbelt' type test0 = N.Add<'2', '10'> // '12' type test1 = N.Add<'0', '40'> // '40' type test2 = N.Add<'0', '40', 's'> // '40' type test3 = N.Add<'0', '40', 'n'> // 40 type test4 = N.Add<'-20', '40', 's'> // '20' type test5 = N.Add<'-20', '40', 'n'> // 20 ```
Add
<function (type parameter) I in type FunctionIndexError<Tests extends unknown[], I extends number = 0>I, 1>>
// Por último, temos o tipo que irá agregar toda a lógica explicada // Caso exista alguma função no nosso array de `Tests`, iremos retornar um objeto de erro. // Se tudo estiver certo, retornamos a assinatura correta do retorno do pipe. type
type CreatePipe<Fns extends Func[], Tests extends unknown[]> = (Tests["length"] extends 0 ? false : OneIsFunction<Tests, Tests[0] extends Func ? true : false, 1>) extends true ? {
    message: "wrong-function";
    errorAt: FunctionIndexError<Tests>;
    functions: Tests;
} : (...params: Parameters<Fns[0]>) => ReturnType<Fns[N.Sub<Fns["length"], 1>]>
CreatePipe
<function (type parameter) Fns in type CreatePipe<Fns extends Func[], Tests extends unknown[]>Fns extends type Func = (...a: any[]) => anyFunc[], function (type parameter) Tests in type CreatePipe<Fns extends Func[], Tests extends unknown[]>Tests extends unknown[]> = type OneIsFunction<Tests extends unknown[], Result extends boolean = false, I extends number = 0> = Result extends true ? true : Tests["length"] extends I ? false : OneIsFunction<Tests, Tests[I] extends Func ? true : false, N.Add<I, 1>>OneIsFunction<function (type parameter) Tests in type CreatePipe<Fns extends Func[], Tests extends unknown[]>Tests> extends true ? {
message: "wrong-function"message: "wrong-function"; errorAt: FunctionIndexError<Tests, 0>errorAt: type FunctionIndexError<Tests extends unknown[], I extends number = 0> = Tests[I] extends Func ? I : FunctionIndexError<Tests, N.Add<I, 1>>FunctionIndexError<function (type parameter) Tests in type CreatePipe<Fns extends Func[], Tests extends unknown[]>Tests> functions: Tests extends unknown[]functions: function (type parameter) Tests in type CreatePipe<Fns extends Func[], Tests extends unknown[]>Tests // Podemos ler: // `Retorne uma função que os parâmetros são referentes // aos parâmetros da primeira função e o retorno seja // o tipo de retorno da última função` } : ((...params: Parameters<Fns[0]>params: type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never
Obtain the parameters of a function type in a tuple
Parameters
<function (type parameter) Fns in type CreatePipe<Fns extends Func[], Tests extends unknown[]>Fns[0]>) => type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any
Obtain the return type of a function type
ReturnType
<function (type parameter) Fns in type CreatePipe<Fns extends Func[], Tests extends unknown[]>Fns[import NN.
type Sub<N1 extends number, N2 extends number> = N1 extends unknown ? N2 extends unknown ? _Sub<IterationOf<N1>, IterationOf<N2>>[0] : never : never
export Sub
Subtract a [[Number]] from another one
@paramN1 Left-hand side@paramN2 Right-hand side@returns`string | number | boolean`@example```ts import {N} from 'ts-toolbelt' type test0 = N.Sub<'2', '10'> // '-8' type test1 = N.Sub<'0', '40'> // '-40' type test2 = N.Sub<'0', '40', 's'> // '-40' type test3 = N.Sub<'0', '40', 'n'> // -40 type test4 = N.Sub<'-20', '40', 's'> // string type test5 = N.Sub<'-20', '40', 'n'> // number ```
Sub
<function (type parameter) Fns in type CreatePipe<Fns extends Func[], Tests extends unknown[]>Fns["length"], 1>]>)
// Finalmente temos a nossa implementação de função pipe const const pipe: <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest) => CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>pipe = <function (type parameter) First in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>First extends type Func = (...a: any[]) => anyFunc, function (type parameter) Second in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Second extends type Unary = (a: any) => anyUnary, function (type parameter) Rest in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Rest extends import FF.
type Narrow<A extends unknown> = A extends [] ? A : NarrowRaw<A>
export Narrow
Prevent type widening on generic function parameters
@paramA to narrow@returns`A`@example```ts import {F} from 'ts-toolbelt' declare function foo<A extends any[]>(x: F.Narrow<A>): A; declare function bar<A extends object>(x: F.Narrow<A>): A; const test0 = foo(['e', 2, true, {f: ['g', ['h']]}]) // `A` inferred : ['e', 2, true, {f: ['g']}] const test1 = bar({a: 1, b: 'c', d: ['e', 2, true, {f: ['g']}]}) // `A` inferred : {a: 1, b: 'c', d: ['e', 2, true, {f: ['g']}]} ```
Narrow
<type Unary = (a: any) => anyUnary[]>>(first: First extends Funcfirst: function (type parameter) First in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>First, second: Second extends Unarysecond: function (type parameter) Second in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Second, ...rest: Rest extends F.Narrow<Unary[]>rest: function (type parameter) Rest in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Rest):
type CreatePipe<Fns extends Func[], Tests extends unknown[]> = (Tests["length"] extends 0 ? false : OneIsFunction<Tests, Tests[0] extends Func ? true : false, 1>) extends true ? {
    message: "wrong-function";
    errorAt: FunctionIndexError<Tests>;
    functions: Tests;
} : (...params: Parameters<Fns[0]>) => ReturnType<Fns[N.Sub<Fns["length"], 1>]>
CreatePipe
<type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0> = Fns["length"] extends I ? Acc : I extends 0 ? Pipe<Fns[I], Fns, [...Acc, (...params: Parameters<First>) => ReturnType<First>], N.Add<I, 1>> : Pipe<...>Pipe<function (type parameter) First in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>First, [function (type parameter) First in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>First, function (type parameter) Second in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Second, ...function (type parameter) Rest in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Rest]>, type ExtractInfo<Fns extends Func[], Transform extends Func[], Acc extends any[] = [], I extends number = 0> = Fns["length"] extends I ? Acc : ExtractInfo<Fns, Transform, [...Acc, Parameters<Fns[I]> extends Parameters<Transform[I]> ? unknown : Fns[I]], N.Add<...>>ExtractInfo<[function (type parameter) First in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>First, function (type parameter) Second in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Second, ...function (type parameter) Rest in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Rest], type Pipe<First extends Func, Fns extends Array<Func | Unary>, Acc extends Func[] = [], I extends number = 0> = Fns["length"] extends I ? Acc : I extends 0 ? Pipe<Fns[I], Fns, [...Acc, (...params: Parameters<First>) => ReturnType<First>], N.Add<I, 1>> : Pipe<...>Pipe<function (type parameter) First in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>First, [function (type parameter) First in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>First, function (type parameter) Second in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Second, ...function (type parameter) Rest in <First extends Func, Second extends Unary, Rest extends F.Narrow<Unary[]>>(first: First, second: Second, ...rest: Rest): CreatePipe<Pipe<First, [First, Second, ...Rest]>, ExtractInfo<[First, Second, ...Rest], Pipe<First, [First, Second, ...Rest]>>>Rest]>>> => ([first: First extends Funcfirst, second: Second extends Unarysecond, ...rest: Rest extends F.Narrow<Unary[]>rest] as type Func = (...a: any[]) => anyFunc[]).Array<Func>.reduce(callbackfn: (previousValue: Func, currentValue: Func, currentIndex: number, array: Func[]) => Func): Func (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@paramcallbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.@paraminitialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
reduce
((acc: Funcacc, fn: Funcfn) => (...args: any[]args: any[]) => fn: (...a: any[]) => anyfn(acc: (...a: any[]) => anyacc(...args: any[]args))) as any;
// Aqui um pequeno teste const const sum: (a: number, b: number) => numbersum = (a: numbera: number, b: numberb: number) => { var console: Consoleconsole.Console.log(...data: any[]): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
({ a: numbera, b: numberb })
return a: numbera + b: numberb } const const pow2: (a: number) => numberpow2 = (a: numbera: number) => var Math: Math
An intrinsic object that provides basic mathematics functionality and constants.
Math
.Math.pow(x: number, y: number): number
Returns the value of a base expression taken to a specified power.
@paramx The base value of the expression.@paramy The exponent value of the expression.
pow
(a: numbera, 2)
const const mutateStringToArray: (a: number, b: number) => ReturnType<(param: number) => ReturnType<(a: number) => number>>mutateStringToArray = const pipe: <(a: number, b: number) => number, (a: number) => number, []>(first: (a: number, b: number) => number, second: (a: number) => number) => CreatePipe<Pipe<(a: number, b: number) => number, [(a: number, b: number) => number, (a: number) => number, ...[]]>, ExtractInfo<[(a: number, b: number) => number, (a: number) => number, ...[]], Pipe<(a: number, b: number) => number, [(a: number, b: number) => number, (a: number) => number, ...[]]>>>pipe( const sum: (a: number, b: number) => numbersum, const pow2: (a: number) => numberpow2 ); const const result: numberresult = const mutateStringToArray: (a: number, b: number) => ReturnType<(param: number) => ReturnType<(a: number) => number>>mutateStringToArray(2, 2) var console: Consoleconsole.Console.log(...data: any[]): void
[MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(const result: numberresult)

Conclusão

Esse tipo deu trabalho, mas conseguimos e ainda descobrimos uma técnica interessante sobre como debuggar os nossos tipos, visto que agora nossa função pipe pode nos alertar sobre o index errado e qual a assinatura da função errada. Por hoje é só isso tudão. Espero que tenham gostado e até a próxima.