Symbol type is not filtered out of keys in types for fromPairs, keys, toPairs, and toPairsIn
Opened this issue · 2 comments
Problem
#50 incorrectly altered the original types for fromPairs
, keys
, toPairs
and toPairsIn
.
The implementation of these functions filter out symbol keys via for ... in
or Object.keys. The original types captured this fact. The altered types do not. This has implications for operations that work with the outputs of these functions that expect symbol key types to be excluded.
Sandbox Demo: https://stackblitz.com/edit/vitejs-vite-tqnrhv?file=src%2Framda-demo.ts&terminal=dev
Implementation References
Great catch! Symbols() are inherently non-enumerable. Do you have a solution in mind? If not I can look into fixing
While looking into this, I found out it's worse than just symbols. The current typing for toPairs
includes any non-enumerable property in its output, including class methods!
Check out this simple instance of a class put through R.toPairs
Now let's put the same code into typescript/play
Simplified here, you get this
import * as R from 'ramda';
class Point {
public x: number;
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
map(fn: (a: number) => number) {
return new Point(fn(this.x), fn(this.y));
}
}
const point = new Point(3, 2);
const asPairs = R.toPairs(point);
// ^? ["x", number] | ["y", number] | ["map", (fn: (a: number) => number) => Point]
// but the value you get is `[["x", 3], ["y", 4]]`
What this means is we can never use keyof
to determine what should be part of the output array of key/value pairs
Because you also would have map
if you use a function to create and object literal:
const makePoint = (x, y) => ({
x,
y,
map: fn => makePoint(fn(x), fn(y))
});
const point2 = makePoint(3, 2);
const asPairs2 = R.toPairs(point2);
// ^? ["x", number] | ["y", number] | ["map", (fn: (a: number) => number) => Point]
// but the value you get is `[["x", 3], ["y", 4], ["map", null]]`
I've always thought that the way Object.entires was typed was just due to very old typescript, before it had the ability to be more specific
entries<T>(o: { [s: string]: T; } | ArrayLike<T>): [string, T][];
But I understand now that it's due to how keyof
does not descriminate against non-enumerables and non-own-properties
I'm thinking that the types for toPairs
and fromPairs
just needs to be typed exactly like Object.entries
and Object.fromEntries
, respectively.
Same with Object.keys
and R.keys
, Object.values
and R.values
, etc
Shitty thing is this is going to be a breaking change