Open joeflateau opened 5 years ago
The built-in Partial
Sorry, I am not super great with Types yet, so I am having trouble understanding this, but..
How does the function partial/curried know that {a:"foo"}
should be a accepting IComplete?
Is it because bar
and baz
are of IComplete, so it infers backwards that curried must accept IComplete too? (Just not used to that way of thinking yet).
Also, Shouldn't curried also be able to accept properties that were passed into partial since they are only "defaults" ?? Because to me it would read that a would have to be omiitted?
So you couldn't do
const bar: IComplete = curried({b:"bar"});
const baz: IComplete = curried({a: "not foo", b:"baz"});
Or am I reading this wrong?
@joeflateau Nice little riddle. I've solved it.
interface Complete {
a: number;
b: number;
}
function curried<PartialOne extends Partial<Complete>>(partialOne: PartialOne) {
return function <PartialTwo extends Omit<Complete, keyof PartialOne>>(partialTwo: PartialTwo) {
return { ...partialOne, ...partialTwo };
}
}
const complete = curried({
a: 2
})({
b: 2
});
const completeCast: Complete = complete;
The trick is to not type the return type of the returned function from curried
. It doesn't matter anyway, because as you can see, it's assignable to Complete
.
Also, sorry for what's basically a bump, but I'm trying to hack away at the long-standing issues here. Hope I helped you anyway, despite the huge time gap. 😛
@resynth1943 haha, no worries. I'm going to need a bit to wrap my head around your solution, but that's awesome
No problem. ♥️ By the way, my solution stops you from passing the same key in both objects, and it's all typed correctly. It should be foolproof. 😛
@resynth1943 where do we go from here? want me to PR?
wrapping in a function to let a type be passed into the curry. still haven't figured out how to make the result of completed() return type T
interface Complete {
a: number;
b: number;
}
function curry<T>() {
return function curried<Curried extends Partial<T>>(curried: Curried) {
return function completed<Completed extends Omit<T, keyof Curried>>(
completed: Completed
) {
return { ...curried, ...completed };
};
};
}
const complete: Complete = curry<Complete>()({
a: 1
})({
b: 2
});
Could cast { ...curried, ...completed } as unknown as T
but that feels wrong
Is this even possible? Because you couldn't pass return type of curried around. It would have to know the solidified value of curried argument to know what it is? For example
const v = JSON.parse(API.get());
const a: ??? = curried<Completed>(v);
const c: Completed = a(somethingElse);
What would you write into a:???
This may be a limitation in the type system, but thought I'd drop this proposal here. The idea here is that there should be some way of expressing that P is an object with keys that are a subset of the keys of T, then those keys that are missing on P from T are required to be supplied as U.
Upvote & Fund