I'd like to use Ramda to clone and update objects in a type-safe way (inspired by this idiom) but I can't get it working in a type-safe way.
Updating a nested object works in a type-safe way perfectly fine:
interface Person {
name: string
department: {
name: string
budget: number
manager?: string
}
}
const personX: Person = {
name: 'Foo Bar',
department: {
name: 'x',
budget: 2000,
},
}
const addManager = (name: string): (input: Person) => Person => assocPath([
'department',
'manager',
], name)
const x = addManager('Michael Scott')(personX) // x is of type `Person`
I can also successfully combine functions using pipe or compose:
const addManager = (name: string): (input: Person) => Person => assocPath([
'department',
'manager',
], name)
const increaseBudget = (budget: number): (input: Person) => Person => assocPath([
'department',
'budget',
], budget)
const addManagerAndUpdateBudget = pipe(addManager('MichaelScott'), increaseBudget(10000))
const x = addManagerAndUpdateBudget(personX) // x is still of type Person
However, as soon as I use clone it fails:
const addManager = (name: string): (input: Person) => Person => assocPath([
'department',
'manager',
], name)
const increaseBudget = (budget: number): (input: Person) => Person => assocPath([
'department',
'budget',
], budget)
const addManagerAndUpdateBudget = pipe(clone, addManager('MichaelScott'), increaseBudget(10000))
const x = addManagerAndUpdateBudget(personX) // Person is not assignable to readonly unknown[]
Might this be an issue with the types? Or am I missing something here?
When using
R.pipe(orR.compose) with other Ramda generic functions (such asR.clone) TS sometimes fails to infer the correct types, and the actual signature of the created function.Note: I'm using Ramda - 0.28.0 and @types/ramda - 0.28.8.
In your case we want Ramda to use this signature - A list of arguments pass to the created function (
TArgs), and then 3 return types of the piped functions (R1,R2,R3):Since Ramda doesn't infer them, we'll need to add them explicitly (sandbox):
Arguments - a tuple with a single
Person, and each return value is also aPerson. We need to state all of them, so that TS would use the specific signature we need.Another option is explicitly type the 1st function in the pipe, so TS can use it to infer the other types (sandbox):