typescript接口动态参数不会没有任何编译

Mil*_*daD 5 typescript

我有一个类型如下,其中如果名称是除"过滤器"以外的任何类型,则"AggrEntry"和"过滤器"的类型为"Aggr".

export interface Aggr {
    [name: string]: AggrEntry;
    filter?: Aggr;
}
Run Code Online (Sandbox Code Playgroud)

但是,除非我改为[name: string]: AggrEntry;,否则ts代码将无法编译[name: string]: any;.

错误是

[ts] Property 'filter' of type 'ResponseAggregation' is not assignable to string index type 'ResponseAggregationEntry'.
Run Code Online (Sandbox Code Playgroud)

逻辑上我猜测typescript尝试分配[name: string]到过滤器,因为过滤器本身可以映射到[name: string].那么我将如何构建我的接口,以便ts编译器知道"name"将永远不会"过滤".

Tit*_*mir 5

如果定义索引器,则所有属性都必须符合接口的返回类型.您可以执行以下操作:

export interface Aggr {
    [name: string]: AggrEntry |Aggr;
    filter?: Aggr;
}
Run Code Online (Sandbox Code Playgroud)

这显然不理想,因为这允许除了filter类型之外的其他字段Aggr.

另一种选择是使用type定义而不是接口,并使用交集类型:

export type Aggr  = {
    [name: string]: AggrEntry;
} & {
    filter?: Aggr;
}

let test : Aggr;
let foo = test.foo // foo is AggrEntry
test.filter // works, is of type Aggr
Run Code Online (Sandbox Code Playgroud)

虽然我们可以按预期访问对象字段,但创建这种类型的对象有点棘手.使用该filter字段创建对象文字将产生与原始文本类似的错误.我们可以使用Object.assign使用对象文字创建该类型的实例:

let test : Aggr = Object.assign({
    foo: new AggrEntry()
}, {
    filter: {
        bar: new AggrEntry()
    }
});
Run Code Online (Sandbox Code Playgroud)

或者我们可以创建一个专用函数来帮助创建,它使用Object.assign:

function createAggr(dynamicPart: {
    [name: string]: AggrEntry;
}, staticPart?: {
    filter?: Aggr;
}) {
    return Object.assign(dynamicPart, staticPart);
}

let test : Aggr = createAggr({
    foo: new AggrEntry()
}, {
    filter: {
        bar: new AggrEntry()
    }
});
Run Code Online (Sandbox Code Playgroud)