mobily / ts-belt

🔧 Fast, modern, and practical utility library for FP in TypeScript.
https://mobily.github.io/ts-belt
MIT License
1.08k stars 30 forks source link

The typing of `D.update` / `D.updateUnsafe` #74

Open ssnielsen opened 1 year ago

ssnielsen commented 1 year ago

I came across a use-case of D.update and D.updateUnsafe that gave me a bit of trouble wrt. its typing.

Example (granted, a bit contrived):

// If I have an object of this shape
const myObject = {
    name: string;
};

// And then use D.update / D.updateUnsafe to change name
const myChangedObject = D.updateUnsafe('name', object => object.name.split(''));

Intuitively, I'd expect the type of myChangedObject.name to be string[], but in practice, it becomes string & string[] (i.e. the original type of name is combined with the return type of the updater function).

Looking at the typings of D.update and D.updateUnsafe, the result of my example definitely makes sense, but I'm wondering a bit why the typings includes the original type of the updated property to begin with 🤔

Happy to hear your takes on this!

JUSTIVE commented 7 months ago

could be fixed easily by changing the signature of the update function with

export declare function update<T, K extends keyof T, R>(dict: T, key: K, fn: (value: T[K]) => R): {[Kx in Exclude<keyof T,K>]:T[Kx]} & {[Kx in K]:R} & {};

here's the result in my local environment

image

the output type could be optimized, by removing & with export type Simplify<T> = {[KeyType in keyof T]: T[KeyType]} & {}; for better readability.

JUSTIVE commented 7 months ago

btw, unlike other fp languages, typescript can infer keyof T type in compile-time, so the value of T[K] should be typeof T[K] instead of Option<T[K]>, I guess.

JUSTIVE commented 5 months ago

revisited this issue, seems D.update has been fixed in 4.0.0, but updateUnsafe isn't.