[WIP] fix(propEq): improve propEq typings#73
Conversation
Nemo108
commented
Oct 15, 2023
- remove unnecessary constraint from propEq value: the function should receive any type values of object, no matter what parameter it received;
- add additional types to use with placeholder
6f999a0 to
f734c70
Compare
|
@Harris-Miller done |
| str: string; | ||
| num: number; | ||
| int: number; | ||
| numLike: number | `${number}`; |
There was a problem hiding this comment.
${number} is a neat trick! Allows strings that only contain number characters, very cool
| }; | ||
| export function propEq<K extends keyof U, const U>(__: Placeholder, name: K, obj: U): (val: WidenLiterals<U[K]>) => boolean; | ||
| export function propEq<K extends keyof U, const U>(val: WidenLiterals<U[K]>, __: Placeholder, obj: U): (name: K) => boolean; | ||
| export function propEq<K extends keyof U, const U>(val: WidenLiterals<U[K]>, name: K, obj: U): boolean; |
There was a problem hiding this comment.
We don't want to WidenLiterals<U[K]> here. When we know the type of U, we want to constrain val to U[K]
type Obj = {
prop: 'foo' | 'bar'
};
// we want to disallow strings other than `'foo'` and `'bar'` here for `val`
propEq('biz', 'prop', obj);WidenLiterals<U[K]> is needed for the curried versions before of how typescript infers types
const doesEqualFoo = propEq('foo', 'prop');
// without `WidenLiterals<U[K]>`, the type would be `Record<'prop', 'foo'>`, but obj is `{ prop: 'foo' | 'bar' }`, which is too wide for just `'foo'`.
// with `WidenLiterals<U[K]>`, the type would be `Record<'prop', string>`, so `obj` is allowed
doesEqualFoo(obj)Typescript doesn't support currying like this that well in general, but we do the best we can with what we have
types/propEq.d.ts
Outdated
| }; | ||
| export function propEq<T, K extends PropertyKey>(val: T, name: K): (obj: Record<K, T>) => boolean; | ||
| export function propEq<K extends keyof U, U>(val: U[K], name: K, obj: U): boolean; | ||
| export function propEq<K extends PropertyKey>(__: Placeholder, name: K): K extends number ? { |
There was a problem hiding this comment.
Instead of the ternary, we do 2 overloads
export function propEq<K extends number>(__: Placeholder, name: K): {
// ...
}
export function propEq<K extends Exclude<PropertyKey, number>>(__: Placeholder, name: K): {
// ...
}
types/propEq.d.ts
Outdated
| ? (array: Array<WidenLiterals<V>>) => boolean | ||
| : (obj: Record<K, WidenLiterals<V>>) => boolean; | ||
| <const U>(__: Placeholder, obj: U): (name: keyof U) => boolean; | ||
| <K extends keyof U, const U>(name: K, obj: U): boolean; |
There was a problem hiding this comment.
I don't think const U in needed here. U should be find.
You need to constrain U and K here though. If typeof U[K] as well. Turns out you don't need WidenLiterals here at all, in fact, it would actually break if U[K] was string | number but you passed a string to val: V.
See here: https://tsplay.dev/m3KbAm
There was a problem hiding this comment.
V extends U[K] ? U : never creates too strict constraint: it fires an error on any string I pass there
But I think I came up with a better solution
f734c70 to
895debc
Compare
* remove unnecessary constraint from propEq value: the function should receive any type values of object, no matter what parameter it received; * add additional types to use with placeholder
895debc to
1e22d85
Compare
|
@Nemo108 I'm having to revert the other This MR is actually of of The additions made to #74 solved a different problem about |
| import { Placeholder } from 'ramda'; | ||
| import { WidenLiterals } from '../util/tools'; |
There was a problem hiding this comment.
| import { Placeholder } from 'ramda'; | |
| import { WidenLiterals } from '../util/tools'; | |
| import { Placeholder, WidenLiterals } from '../util/tools'; |
|
|
||
| export function propEq(__: Placeholder): never; | ||
| export function propEq<const V>(val: V): { | ||
| <K extends number>(name: K): <U extends any[]>(array: V extends U[K] ? V[] : never) => boolean; |
There was a problem hiding this comment.
Ah crap, I missed this when I left that other comment about this MR not being a problem
array: V extends U[K] ? V[] : never
This is the thing we can't have. It breaks combining with other functions, egR.filter(R.propEq('type', 'something')). The predicate type signatures don't match because of the : never