Reputation: 190
I have different types of views, and the views vary in what properties they have and what properties can be changed. I've tried to create an updateView function where a view and some changes are passed in, merged, and then the view is updated on the backend. The function should restrict what changes are passed in based on what type of view is passed in, but this isn't working correctly. I've posted an example below.
How can I change the UpdateView interface to properly restrict the changes that can be passed in?
interface BaseView {
immutableProp?: string;
mutableProp?: string;
name: string;
isCustom: boolean;
}
interface StandardView extends BaseView {
isCustom: false;
}
interface CustomView extends BaseView {
isCustom: true;
}
type View = StandardView | CustomView
type StandardMutableFields = Partial<Pick<StandardView, "mutableProp">>
type CustomMutableFields = Partial<Pick<CustomView, "mutableProp" | "name">>
interface UpdateView {
<T extends View>(viewToChange: T, changes: T extends CustomView ? CustomMutableFields : StandardMutableFields): T
}
const updateView: UpdateView = (viewToChange, changes) => {
const updatedView = { ...viewToChange, changes };
// SAVE TO SERVER
return updatedView;
}
const changeName = (view: View, name: string) => {
updateView(view, { name: "this is allowed but shouldn't be" }) // should require a check to ensure the view is custom
}
Upvotes: 0
Views: 36
Reputation: 249536
I think the simplest solution here (at least from what I see in the question) is to drop the conditional types and the generic function and just use overloads.
Overloads intrinsically can't be called with a union of possible parameter types, so the call be with a CustomView
or with a StandardView
but not a union of the two, naturally forcing you to discriminate between the two before you perform the call:
interface UpdateView {
(viewToChange: CustomView, changes: CustomMutableFields): CustomView
(viewToChange: StandardView, changes: StandardMutableFields): StandardView
}
const updateView: UpdateView = (viewToChange: CustomView | StandardView, changes : CustomMutableFields | StandardMutableFields) => {
const updatedView = { ...viewToChange, changes };
// SAVE TO SERVER
return updatedView as any;
}
const changeName = (view: View, name: string) => {
updateView(view, { name: "this is allowed but shouldn't be" }) // err
if (view.isCustom) {
updateView(view, { name: "this is allowed but shouldn't be" }) // ok
}
}
Upvotes: 1