Evitare l'esplosione del sovraccarico della funzione
Aug 22 2020
TypeScript fornisce un modo per evitare questo tipo di esplosione di sovraccarico del metodo e, così facendo, fornisce l'indipendenza dai tipi a un numero illimitato di vararg?
type Operator<FROM, TO> = (source: Stream<FROM>) => Stream<TO>
class Stream<V> {
// ...
pipe<A>(operator: Operator<VALUE, A>): Stream<A>
pipe<A, B>(op1: Operator<VALUE, A>, op2: Operator<A, B>): Stream<B>
pipe<A, B, C>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>): Stream<C>
pipe<A, B, C, D>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>): Stream<D>
pipe<A, B, C, D, E>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>): Stream<E>
pipe<A, B, C, D, E, F>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>): Stream<F>
pipe<A, B, C, D, E, F, G>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>, op7: Operator<F, G>): Stream<G>
pipe<A, B, C, D, E, F, G, H>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>, op7: Operator<F, G>, op8: Operator<G, H>): Stream<H>
pipe<A, B, C, D, E, F, G, H, I>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>, op7: Operator<F, G>, op8: Operator<G, H>, op9: Operator<H, I>): Stream<I>
pipe<A, B, C, D, E, F, G, H, I, J>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>, op7: Operator<F, G>, op8: Operator<G, H>, op9: Operator<H, I>, op10: Operator<I, J>): Stream<J>
pipe<A, B, C, D, E, F, G, H, I, J, K>(op1: Operator<VALUE, A>, op2: Operator<A, B>, op3: Operator<B, C>, op4: Operator<C, D>, op5: Operator<D, E>, op6: Operator<E, F>, op7: Operator<F, G>, op8: Operator<G, H>, op9: Operator<H, I>, op10: Operator<I, J>, ...restOps: Operator<unknown, unknown>[]): Stream<K>
pipe<TO_VALUE>(operator: Operator<VALUE, unknown>, ...restOperators: Operator<unknown, unknown>[]): Stream<TO_VALUE> {
return restOperators.reduce((stream, operator) => operator(stream), this as Stream<unknown>) as Stream<TO_VALUE>
}
}
Notare che Operator
il tipo di output di ciascuno è il Operator
tipo di input successivo .
Risposte
3 MingweiSamuel Sep 08 2020 at 07:31
È possibile.
Ecco un esempio funzionante che richiede i tipi di tupla TypeScript 4. L'idea è quella di utilizzare un array generico T
per tenere traccia di ogni tipo consecutivo per assicurarsi che gli operatori siano d'accordo.
Ho basato questa risposta su questo commento di @jcalz.
type Operator<FROM, TO> = (source: Stream<FROM>) => Stream<TO>
type Prev<T extends any[], K, D> = K extends keyof [ D, ...T ] ? [ D, ...T ][K] : never;
type Operators<VALUE, T extends any[]> = {
[K in keyof T]: Operator<Prev<T, K, VALUE>, T[K]>
};
type PipeResult<T extends any[]> = T extends [ ...infer _, infer U ] ? Stream<U> : never;
class Stream<VALUE> {
x?: VALUE; // Needed to make sure Stream<X> doesn't always extend Stream<Y>.
pipe<T extends any[]>(...operators: Operators<VALUE, T>): PipeResult<T> {
return operators.reduce<Stream<unknown>>((stream, operator) => operator(stream), this) as PipeResult<T>;
}
}
Collaudo:
const OpA: Operator<number, 'hi'> = null as any;
const OpB: Operator<string, 'hello'> = null as any;
const OpC: Operator<string, Date> = null as any;
const OpD: Operator<1521, string> = null as any;
const OpE: Operator<5, 6> = null as any;
const OpF: Operator<6, 7> = null as any;
const NumberStream = new Stream<number>();
// x0: Stream<Date>
const x0 = NumberStream.pipe(OpA, OpB, OpC);
// x1: Stream<"hello">
const x1 = NumberStream.pipe(
OpA, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB,
OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB,
OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB, OpB);
// Error on arg 3.
const x2 = NumberStream.pipe(OpA, OpC, OpC);
// Error on arg 1.
const x3 = NumberStream.pipe(OpD, OpE, OpF);
Collegamento al parco giochi
Vecchia risposta negativa: Playground Link