The updateObject function below takes in oldObject of type T and newValues of type Partial<T>, and then assigns any of the values present innewValues to oldObject.
My problem is that if newValues contains properties not present in oldObject, my compiler throws an error. How can I express to the compiler that I want newValues to be reduced to only the properties present in oldObject?
Problematic code
In this code, newValues is of type Partial<Point> and point is of type ThreatPoint.
updateObject(point, newValues);
Error Message
The error I receive says:
Argument of type '(point: ThreatPoint) => (ThreatPoint & Partial<ThreatPoint>) | (RoutePoint & Partial<...>)' is not assignable to parameter of type '(item: ThreatPoint) => ThreatPoint'.
Type '(ThreatPoint & Partial<ThreatPoint>) | (RoutePoint & Partial<...>)' is not assignable to type 'ThreatPoint'.
Types of property 'category' are incompatible.
Type 'Category.ROUTE_POINT' is not assignable to type 'Category.THREAT'.
updateObject Function
static updateObject = <T>(oldObject: T, newValues: Partial<T>) => {
// Encapsulate the idea of passing a new object as the first parameter
// to Object.assign to ensure we correctly copy data instead of mutating
return Object.assign({}, oldObject, newValues);
};
Types/Interfaces
export interface BasicPoint {
category: Category;
id: string;
position: Coordinate;
title: string;
type: PointType;
}
export enum RoutePointType {
START = 'START',
FINISH = 'FINISH',
}
export enum ThreatPointType {
OBSTACLE = 'OBSTACLE',
RIVER = 'RIVER',
}
export type PointType = RoutePointType | ThreatPointType;
export enum Category {
ROUTE_POINT = 'ROUTE_POINT',
THREAT = 'THREAT',
}
export interface RoutePoint extends BasicPoint {
category: Category.ROUTE_POINT;
speed: number;
type: RoutePointType;
}
export interface ThreatPoint extends BasicPoint {
category: Category.THREAT;
type: ThreatPointType;
}
export type Point = RoutePoint | ThreatPoint;
Object.assignis not the best choice because it mutates{}