Description
Bug Report
Metatype KeysWithoutStringIndex
(see snippet) that maps keyof T
to object after removing [string]
index signature and then infers keyof
the new object to key type of "non-index" keys, always produces subset of keyof T
. This code reports error when upgrading to TS 4.2 and this change is not mentioned in the highlighted breaking changes in the release notes.
Current workaround is to intersect the result value with keyof T
to fix the error via (...) & keyof T
.
🔎 Search Terms
keyof, 4.2, regression, index signature, breaking change
🕗 Version & Regression Information
Problem present since 4.2, not fixed in Nightly (4.3.0-dev.20210323).
Working in recent prior minor versions available form playground: 4.1, 4.0, 3.9, 3.8
- This changed between versions 4.1 and 4.2
⏯ Playground Link
💻 Code
// Return keyof type without string index signature
type KeysWithoutStringIndex<T> = {
[K in keyof T]: string extends K ? never : K } extends { [_ in keyof T]: infer U }
? U
: never
// Only "foo" | "bar" as expected, [string] index signature removed
type test = KeysWithoutStringIndex<{ [index: string]: string; foo: string; bar: 'baz' }>
// KeysWithoutStringIndex<T> will always be a subset of keyof T, but is reported as unassignable
export type RemoveIdxSgn<T> = Pick<T, KeysWithoutStringIndex<T>>
// ERROR:
// Type 'KeysWithoutStringIndex<T>' does not satisfy the constraint 'keyof T'.
// Type 'unknown' is not assignable to type 'keyof T'.(2344)
🙁 Actual behavior
Code caused error after update that was not mentioned in notable breaking changes but was working previously.
Type 'KeysWithoutStringIndex<T>' does not satisfy the constraint 'keyof T'.
Type 'unknown' is not assignable to type 'keyof T'.(2344)
🙂 Expected behavior
No error or error even on previous versions.