Created
July 30, 2025 05:13
-
-
Save ryangoree/333c37ce867c026d289c00a038ceabad to your computer and use it in GitHub Desktop.
Get a union of all possible keys for `T` without losing type inference for literal keys.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* One of the *explicit* property names of {@linkcode T}, with any `string` or | |
* `number` index signatures stripped out. | |
* | |
* @example | |
* ```ts | |
* type A = LiteralKey<{ | |
* [k: string]: any; | |
* id: string; | |
* }>; | |
* // => "id" | |
* | |
* type B = LiteralKey< | |
* | { | |
* [k: string]: any; | |
* name: string; | |
* } | |
* | { [k: number]: any; 0: number } | |
* >; | |
* // => "name" | 0 | |
* ``` | |
*/ | |
export type LiteralKey<T> = T extends T | |
? keyof { | |
[K in keyof T as K & Exclude<number | string, K>]: any; | |
} | |
: never; | |
/** | |
* Get a union of all possible keys for {@linkcode T}, including literal | |
* properties and any explicit `string` or `number` index signatures. | |
* | |
* It distributes over unions and preserves literal keys alongside index | |
* signatures, ensuring nice type inference for autocompletion. | |
* | |
* @example | |
* ```ts | |
* type A = IndexableKey<{ | |
* [k: string]: any; | |
* id: string; | |
* }>; | |
* // => "id" | (string & {}) | |
* | |
* type B = IndexableKey< | |
* | { | |
* [k: string]: any; | |
* name: string; | |
* } | |
* | { [k: number]: any; 0: number } | |
* >; | |
* // => "name" | 0 | (string & {}) | (number & {}) | |
* ``` | |
*/ | |
export type IndexableKey<T> = | |
| LiteralKey<T> | |
| (T extends T | |
? // Using array types to perform structural comparisons and prevent | |
// simplification of the union to a single type. | |
| (string[] extends (keyof T)[] ? string & {} : never) | |
| (string[] extends (keyof T)[] | |
? never | |
: number[] extends (keyof T)[] | |
? number & {} | |
: never) | |
: never); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment