The simplest你可以做的是:
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
仍然被认为是一种接受string
和一个可选的number
,即使类型QueryMap['foo']['params']
isn't.
如果您指定某些不可分配给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
and U
在这里工作(这就是当你使用时发生的情况any
)。如果你需要更多地锁定它,你可以尝试让 TypeScript 推断出一组P
and U
值或警告您,如果它不能,但这并不简单。
为了完整起见,我将这样做......使用条件类型 https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#conditional-types推断P
and 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>
对于大多数用途来说可能已经足够了。
好的,希望有帮助;祝你好运!