4 ms·
It seems to be stem from `Record` being contravariant in its Key type, right? const taskCounts = { work: 10, home: 5, personal: 3 }; This probably has the d
by planede 3y ago
It seems to be stem from `Record` being contravariant in its Key type, right?
const taskCounts = { work: 10, home: 5, personal: 3 };
This probably has the deduced type of `Record<"work" | "home" | "personal", number>`.
I wonder if there is a hole in the type system that could be filled with an `ExactKeyTypeRecord<K, V>`, which is invariant in K and is a subtype of `Record<K, V>`. Maybe this could have Object.keys() defined as expected.
I have no experience with TS, but I believe Python's TypedDict has a bunch of similar holes in the type system that could be mitigated with a bit more elaborate type hierarchies.
- STRML 3y agoFlowtype works like this out of the box. In my opinion, it's a much better default.
- planede 3y agoHuh, nice! Looking at the documentation[1], I assume this is the difference between "exact object types" and "inexact object types". I though about bringing this up for Python TypedDict, so I'm glad there is an actual precedent. https://flow.org/en/docs/types/objects/ https://flow.org/en/docs/types/objects/
- headbee 3y agoI believe that would be covariant: `'home' | 'work'` is a subtype of `string`, and `Record<'home' | 'work', number>` is assignable to `Record<string, number>` so the subtype relationship is preserved.
- planede 3y agoI don't follow how this parameter works then in Record: const taskCounts = { work: 10, home: 5, personal: 3 }; const what : Record<string, number> = taskCounts; // OK, covariance? const the : Record<"work" | "home", number> = taskCounts; // Also OK, contravariance? const hell : Record<"work" | "home" | "personal" | "hello", number> = taskCounts; // This is an error https://www.typescriptlang.org/play?#code/MYewdgzgLgBFCGEDWBhEBXMUIwLwwG8YB3EAJyQC4YBGABgBoYALEAWwFNqBWJgBw5kI4eABtqAZhgBfANwAoeaEixizeLGoAlDqDIATADzQyASzABzJmHRsARoIB8eOIlQYsEWTAD0PmKAAbvBm8GDAHAD8SuDQcMwcMNq65EYARKQUaTAAPjBprJxp1rYOZM74CMhomNjefgHgUGTwwaHhUTEqLByiokkwOnrpmUjZeQXsHOP5AkIiojMFvaIgxTA29k4uVe61XkA https://www.typescriptlang.org/play?#code/MYewdgzgLgBFCGEDWB...
- headbee 3y agoI think you were originally correct and that `Record<string, number>` was not a good example. I would guess that union literals and primitives are handled differently by the compiler in this case, perhaps because a record with keys of every possible string is impossible it may have a special condition to skip some typing rules. In fact, `Record<number, number>` is assignable to `Record<string, number>`.