您可以做的最简单的事情是:
export type QueryMap = {
[k: string]: IQuery<any, any>
};
它不是完全类型安全的,但它与您要表示的内容相差不远。如果您不想丢失 type 值的类型信息QueryMap
,请允许编译器推断更窄的类型并使用通用辅助函数来确保它是有效的QueryMap
,如下所示:
const asQueryMap = <T extends QueryMap>(t: T) => t;
const queryMap = asQueryMap({
foo: {
request: "a",
params(p: string, u?: number) { return {} },
key(p: string, u?: number) { return "hey" },
forceRequest: true
}
});
尽管类型不是,但queryMap.foo.params
仍然知道该值是接受 astring
和 optional的方法。number
QueryMap['foo']['params']
如果您指定不可分配给 a 的内容,QueryMap
您将收到错误消息:
const bad = asQueryMap({
foo: {
request: "a",
params(p: string, u?: number) { return {} },
key(p: string, u?: number) { return "hey" },
forceRequest: true
},
bar: {
request: 123,
params(p: number, u?: string) {return {}},
key(p: number, u?: string) {return "nope"},
forceRequest: false
}
}); // error! bar.request is a number
这里显示了不完全类型安全的问题:
const notExactlySafe = asQueryMap({
baz: {
request: "a",
params(p: number, u?: string) { return {} },
key(p: string, u?: number) { return "hey" },
forceRequest: true
}
});
这是可以接受的,即使没有一致的合理值P
和U
在这里有效(这就是您使用 时发生的情况any
)。如果您需要更多地锁定它,您可以尝试让 TypeScript从值中推断出P
和U
值的集合,或者如果不能,则警告您,但这不是直接的。
为了完整起见,这里就是我会做...使用条件类型来推断P
,并U
为您的每个元素QueryMap
通过检查params
方法,然后验证key
方法进行匹配。
const asSaferQueryMap = <T extends QueryMap>(
t: T & { [K in keyof T]:
T[K]['params'] extends (p: infer P, u?: infer U) => any ? (
T[K] extends IQuery<P, U> ? T[K] : IQuery<P, U>
) : never
}
): T => t;
现在以下仍然有效:
const queryMap = asSaferQueryMap({
foo: {
request: "a",
params(p: string, u?: number) { return {} },
key(p: string, u?: number) { return "hey" },
forceRequest: true
}
});
虽然这现在将是一个错误:
const notExactlySafe = asSaferQueryMap({
baz: {
request: "a",
params(p: number, u?: string) { return {} },
key(p: string, u?: number) { return "hey" },
forceRequest: true
}
}); // error, string is not assignable to number
这会略微增加您的类型安全性,但会牺牲 类型中相当复杂的类型杂耍asSaferQueryMap()
,所以我不知道这是否值得。 IQuery<any, any>
对于大多数用途来说可能已经足够了。
好的,希望有帮助;祝你好运!