better-typescript-lib
better-typescript-lib copied to clipboard
Issue when using `object` with `Object.entries` and `Object.values`
As shown above, this overload included in better-typescript-lib cause an issue when applied to an object without a specified key or value type. The overload seems to match too eagerly, returning a type with never instead of falling through to the more generic call signatures.
Here's one way to fix it, although I don't know if it's the best fix: TS Playground
The same fix seems to work for Object.entries as well.
Note: This issue is unrelated to https://github.com/uhyo/better-typescript-lib/pull/31 (but maybe worth mentioning there)
For posterity and to avoid having to check the playground, the problematic overloads are:
interface ObjectConstructor {
values<K extends PropertyKey, V>(o: Record<K, V>): V[];
entries<K extends PropertyKey, V>(o: Record<K, V>): [string, V][];
}
and the proposed fix:
interface ObjectConstructor {
values<K extends PropertyKey, V>(o: [V] extends [never] ? never : Record<K, V>): V[];
entries<K extends PropertyKey, V>(o: [V] extends [never] ? never : Record<K, V>): [string, V][];
}
This might be a better fix, targeting object and wider types specifically:
interface ObjectConstructor {
values<K extends PropertyKey, V>(o: object extends Record<K, V> ? never : Record<K, V>): V[];
entries<K extends PropertyKey, V>(o: object extends Record<K, V> ? never : Record<K, V>): [string, V][];
}
Hmm, it seems that object and any record with never-typed keys mutually extend each other:
type foo = object extends Record<never, unknown> ? true : false; // true
type bar = Record<never, unknown> extends object ? true : false; // true
so to be minimally invasive I guess we want something like
interface ObjectConstructor {
values<K extends PropertyKey, V>(o: [K, V] extends [never, never] ? never : Record<K, V>): V[];
entries<K extends PropertyKey, V>(o: [K, V] extends [never, never] ? never : Record<K, V>): [string, V][];
}
so that records with never-type keys or never-type values still yield the expected result.
Putting it together with https://github.com/uhyo/better-typescript-lib/pull/31:
type KeyToString<K extends PropertyKey> = K extends string ? K : K extends number ? `${K}` : never;
interface ObjectConstructor {
keys<K extends PropertyKey, V>(o: [K, V] extends [never, never] ? never : Record<K, V>): KeyToString<K>[];
values<K extends PropertyKey, V>(o: [K, V] extends [never, never] ? never : Record<K, V>): V[];
entries<K extends PropertyKey, V>(o: [K, V] extends [never, never] ? never : Record<K, V>): [KeyToString<K>, V][];
}
A fix has been released as v2.8.0. Thank you for reporting!