如何从类型中排除索引签名?

Tal*_*ite 8 typescript

如果我按如下方式定义我的类型,它将遵循我想要的行为。

interface Foo {}

interface Bar {
    a: string;
    b: boolean;
    c: Foo;
}

type x = keyof Bar; // "a" | "b" | "c"
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试添加索引签名,它会丢失我所有的预定义成员。

interface Bar {
    [index: string]: any;
}

type x = keyof Bar; // string | number
Run Code Online (Sandbox Code Playgroud)

有没有办法在 TypeScript 中正确地做到这一点?

类似于:

type x = Exclude<Bar, { [index: string]: any }>; // never
Run Code Online (Sandbox Code Playgroud)

编辑 我尝试了类似于 Jake 的解决方案并得到了这个:

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
Run Code Online (Sandbox Code Playgroud)

Foo1不起作用,由于某种原因,它的类型信息变为{}. Foo2 确实有效,但智能感知并没有说明Foo2类型的变量Foo2。他们反而有Indexable<BaseFoo>

我真的很想尝试对我的用户隐藏这种类型的按摩。不幸的是,让他们从Indexable<T>到来回转换是不可行的T

bas*_*rat 5

回答

对于具有索引签名的内容,没有通用的方法可以做到这一点。

选择

添加索引签名之前获取密钥:

interface Foo {}

interface BarCore {
    a: string;
    b: boolean;
    c: Foo;
}


type Bar = BarCore & {
    [index: string]: any;
}

type X = keyof BarCore; // a|b|c
Run Code Online (Sandbox Code Playgroud)

更多的

PS:尽量不要在根级别将索引签名与有效道具混合。而是使用嵌套对象模式