Edit: Since Typescript 4.1 there is a way of doing this directly with Key Remapping, avoiding the Pick
combinator. Please see the answer by Oleg where it's introduced.
type RemoveIndex<T> = {
[ K in keyof T as string extends K ? never : number extends K ? never : K ] : T[K]
};
It is based on the fact that 'a' extends string
but string
doesn't extends 'a'
.
There is also a way to express that with TypeScript 2.8's Conditional Types.
interface Foo {
[key: string]: any;
[key: number]: any;
bar(): void;
}
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 FooWithOnlyBar = Pick<Foo, KnownKeys<Foo>>;
You can make a generic out of that:
// Generic !!!
type RemoveIndex<T extends Record<any,any>> = Pick<T, KnownKeys<T>>;
type FooWithOnlyBar = RemoveIndex<Foo>;
For an explanation of why exactly KnownKeys<T>
works, see the following answer:
https://stackoverflow.com/a/51955852/2115619
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…