If I define my types as follows, it follows my desired behavior.
interface Foo {}
interface Bar {
a: string;
b: boolean;
c: Foo;
}
type x = keyof Bar; // "a" | "b" | "c"
However, if I try to add an index signature, it loses all my predefined members.
interface Bar {
[index: string]: any;
}
type x = keyof Bar; // string | number
Is there a way to do this properly in TypeScript?
Something similar to:
type x = Exclude<Bar, { [index: string]: any }>; // never
EDIT I tried something similar to Jake's solution and got this:
interface Indexable<T> {
[index: string]: any;
}
type BaseType<T> = T extends Indexable<infer U> ? U : never;
interface BaseFoo {
Name: string;
}
interface Foo1 extends Indexable<BaseFoo> {}
type Foo2 = Indexable<BaseFoo>;
type base1 = BaseType<Foo1>; // {}
type base2 = BaseType<Foo2>; // BaseFoo
Foo1
does not work, for some reason the type info for that becomes {}
.
Foo2
does work, but intellisense does not say Foo2
for variables of type Foo2
. They instead have Indexable<BaseFoo>
.
I would really like to try to hide this type massaging from my users. And unfortunately, it's not feasible to ask them to cast back and forth from Indexable<T>
to T
.