I try to create a class to abstract the map
function of Arrays to works transparently on single values.
export class Container<T> {
value: T;
constructor(value: T) {
this.value = value;
}
map<U>(f: (x: T extends Array<infer R> ? R : T) => U): Container<T extends Array<any> ? Array<U> : U> {
if (Array.isArray(this.value)) {
const mapped = this.value.map(f);
return new Container(mapped); // <-- Error A here
}
return new Container<U>(f(this.value /* <-- Error B here */)); // <-- Error C here
}
unwrap(): T {
return this.value;
}
}
//Sample usage
const sayHello = (name: string) => `Hello ${name}`;
const shout = (str: string) => str.toUpperCase();
const a = new Container("Toto").map(sayHello).map(shout).unwrap() // HELLO TOTO
const b = new Container(["Harry", "Ron", "Hermione"]).map(sayHello).map(shout).unwrap() // ["HELLO HARRY", "HELLO RON", "HELLO HERMIONE"]
But typescript complains, and i don't understand why the type doesn't match
// Error A
Type 'Container<U[]>' is not assignable to type 'Container<T extends any[] ? U[] : U>'.
Type 'U[]' is not assignable to type 'T extends any[] ? U[] : U'.ts(2322)
// Error B
Argument of type 'T' is not assignable to parameter of type 'T extends (infer R)[] ? R : T'
// Error C
Type 'Container<U>' is not assignable to type 'Container<T extends any[] ? U[] : U>'.
Type 'U' is not assignable to type 'T extends any[] ? U[] : U'
I now I can "fix" it with any
but look for a cleaner solution