Utility type `KnownKeys<T>` broken on TypeScript 4.3
See original GitHub issueDescription
The following code no longer compiles after upgrading from TypeScript 4.2.4 to 4.3.2
(Click here to expand)
import { App } from "@slack/bolt";
const app = new App();
app.command("/say_hi", async ({ ack, respond }) => {
await ack();
await respond({
blocks: [{ type: "section", text: { text: "hi", type: "plain_text" } }],
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// error TS2345: Argument of type '{ blocks: { type: string; text: { text: string; type: string; }; }[]; response_type: "ephemeral"; }' is not assignable to parameter of type 'string | RespondArguments'.
// Object literal may only specify known properties, and 'blocks' does not exist in type 'RespondArguments'. });
response_type: "ephemeral",
});
});
I have narrowed down the problem to the utility type KnownKeys<T>
in /src/types/helpers.ts
.
type type KnownKeys<T> = {
[K in keyof T]: string extends K ? never : number extends K ? never : K;
} extends { [_ in keyof T]: infer U }
? U
: never;
type Foo = {
foo: "Foo";
bar: "Bar";
[key: string]: any;
};
type Result = KnownKeys<Foo>;
// type of `Result` is `never` in TypeScript 4.3.2
// type of `Result` is `"foo" | "bar"` in TypeScript 4.2.4
KnownKeys<T>
failing to resolve the keys has caused RespondArguments
in /src/types/utilities.ts
to omit the property “blocks” by calling Pick
with never
as the 2nd type argument:
type RespondArguments = Pick<
ChatPostMessageArguments,
Exclude<KnownKeys<ChatPostMessageArguments>, 'channel' | 'text'> // <-- KnownKeys<T> fails here
> & { /* ... */ };
…which in turn causes RespondFn
to report an error when “blocks” is included in respond({ /* ... */ })
What type of issue is this? (place an x
in one of the [ ]
)
- bug
- enhancement (feature request)
- question
- documentation related
- example code related
- testing related
- discussion
Requirements (place an x
in each of the [ ]
)
- I’ve read and understood the Contributing guidelines and have done my best effort to follow them.
- I’ve read and agree to the Code of Conduct.
- I’ve searched for any related issues and avoided creating a duplicate issue.
Bug Report
Filling out the following details about bugs will help us solve your issue sooner.
Reproducible in:
package version: 3.3.0
node version: 15.12.0
OS version(s): OSX 11.3.1
Steps to reproduce:
(See description)
Also, /types-tests/utilities.test-d.ts
should show an error after upgrading to TypeScript 4.3 (See attachment)
Expected result:
KnownKeys<T>
should work properly in TypeScript 4.3.
Maybe add a test case to cover type Result = KnownKeys<Foo>;
should not infer type never
.
Actual result:
KnownKeys<T>
infers never
in TypeScript 4.3.
Attachments:
Issue Analytics
- State:
- Created 2 years ago
- Reactions:13
- Comments:9 (8 by maintainers)
I’ve looked into the implementation of
KnownKeys<T>
a bit, the current implementation (after formatting by hand):The first clause reads as “Given a type
T
, for each key asK
inT
, ifstring extends K
ornumber extends K
then returnnever
, else returnK
”, the second clause reads as "Given the result object type of the first clause (which is an object type{ [Key in keyof T]: Key | never }
), return a union type of the values of this result object type.I think this implementation can be further simplified to the following for better readability:
…which essentially does the same thing, doing the
string extends
andnumber extends
check and returningK
, then usingkeyof T
to index the intermediate object (but now without needinginfer
!)@lokshunhung thats the only implementation that worked for me, thank you 😃 The other KnownKeys examples returned a never type on my machine unfortunately.