I want a function to take partial input. However, it contains a variable named style
whose values can only be outline
or fill
like:
export type TrafficSignalStyle = 'outline' | 'fill'
let style: TrafficSignalStyle
But the problem is when I do Partial<TrafficSignalStyle>
, it converts TrafficSignalStyle
to 'outline' | 'fill' | undefined
which is not what I want.
I want a single function that takes 3 inputs namely style
, colors
& position
& changes only whatever input is passed. So if I pass style
like updateTrafficSignal({ style: e.target.value as TrafficSignalStyle })
then it keeps colors
& position
the same as it were before.
Here's what the related files look like:
types.ts
export type TrafficSignalButtons = {
close: string
minimize: string
maximize: string
}
export type TrafficSignalPosition = {
close: Point
minimize: Point
maximize: Point
}
export type TrafficSignalStyle = 'outline' | 'fill'
export type TrafficSignal = {
style: TrafficSignalStyle
colors: Array<TrafficSignalButtons>
position: TrafficSignalPosition
}
export interface IFrameItStore {
trafficSignal: TrafficSignal
updateTrafficSignal(trafficSignal: Partial<TrafficSignal>): void
}
FrameItStore.ts
import { action, makeObservable, observable } from 'mobx'
import type { IFrameItStore, TrafficSignal } from './types'
export class FrameItStore implements IFrameItStore {
trafficSignal: TrafficSignal = {
style: 'outline',
colors: [
{
close: '#EF4444',
minimize: '#FBBE25',
maximize: '#49DE80',
},
{
close: 'black',
minimize: 'blue',
maximize: 'orange',
},
],
position: {
close: { x: 100 + 20, y: 20 },
minimize: { x: 100 + 2 * 20, y: 20 },
maximize: { x: 100 + 3 * 20, y: 20 },
},
}
constructor() {
makeObservable(this, {
trafficSignal: observable,
updateTrafficSignal: action.bound,
})
}
updateTrafficSignal(trafficSignal: Partial<TrafficSignal>) {
if (trafficSignal.style) this.trafficSignal.style = trafficSignal.style
if (trafficSignal.colors) this.trafficSignal.colors = trafficSignal.colors
if (trafficSignal.position) this.trafficSignal.position = trafficSignal.position
}
}
Options.tsx
import * as React from 'react'
import { observer } from 'mobx-react'
import { useFrameItStore } from './store'
import type { Padding, TrafficSignal, TrafficSignalStyle } from './types'
interface IProps {
className?: string
}
export const Options = observer((props: IProps) => {
const frameItStore = useFrameItStore()
const trafficSignal: TrafficSignal = frameItStore.trafficSignal
const padding: Padding = frameItStore.padding
const updateTrafficSignal: (trafficSignal: Partial<TrafficSignal>) => void =
frameItStore.updateTrafficSignal
const updatePadding: (padding: Padding) => void = frameItStore.updatePadding
return (
<div>
<h2>Traffic Signal Style:</h2>
<select
value={trafficSignal.style}
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
const style = e.target.value as TrafficSignalStyle
updateTrafficSignal({ style })
}}
>
<option value="outline">Outline</option>
<option value="fill">Fill</option>
</select>
</div>
)
})
However, I get an error saying
TS2322: Type '(trafficSignal: TrafficSignal) => void' is not assignable to type '(trafficSignal: Partial<TrafficSignal>) => void'.
Types of parameters 'trafficSignal' and 'trafficSignal' are incompatible. Type 'Partial' is not assignable to type 'TrafficSignal'. Types of property 'style' are incompatible. Type '"outline" | "fill" | undefined' is not assignable to type 'TrafficSignalStyle'. Type 'undefined' is not assignable to type 'TrafficSignalStyle'.
Which makes sense but how do I pass in only 1 parameter & have that change only that parmeter & not the others.
If I remove Partial
then I get
Argument of type '{ style: TrafficSignalStyle; }' is not assignable to parameter of type 'TrafficSignal'. Type '{ style: TrafficSignalStyle; }' is missing the following properties from type 'TrafficSignal': colors, position
Which also makes sense. But still doesn't solve my problem.
I want a single function to change all 3 params & only 1 will be passed at a time.
How do I do it?