我有这个简单的功能:
export function toDictionary<T>(items: T[], getKey: (item: T) => string) {
const result = [...items];
for (const item of items) {
const key = getKey(item);
if(result[key]) {
throw new Error(`Key value ${key} is not unique.`);
}
result[key] = item;
}
return result;
}
我想以智能感知将向我展示属性的方式指定此函数的返回类型。
示例:
const dictionary = toDictionary([{
type: 'list',
url: 'http://example/list'
}, {
type: 'details',
url: 'http://example/{0}/details'
}], x => x.type);
打字稿应该知道dictionary.list
和dictionary.details
存在。
这有可能吗?我愿意更改此实现代码中的任何内容。所有数据都在构建时可用,即是静态的硬编码数据。
答案 0 :(得分:2)
第一个问题是让编译器为可能会最终用作字典键的属性推断文字类型。如果将文字分配给扩展了可以缩小为文字的类型的通用类型参数的位置,则编译器将推断文字类型。
因此,在本例中,如果使用此约束,则将获得type
:T extends Record<string, P | object>, P extends PropertyKey
的文字类型。
如果我们还为getKey
函数的返回类型添加一个类型参数(例如K
),则可以将结果键入为T[] & Record<K, T>
。
将其放在一起,我们得到:
export function toDictionary<T extends Record<string, P | object>, P extends PropertyKey, K extends Extract<T[keyof T], PropertyKey>>(items: T[], getKey: (item: T) => K): T[] & Record<K, T> {
const result = [...items];
for (const item of items) {
result[getKey(item) as number] = item;
}
return result as T[] & Record<K, T>;
}
const dictionary = toDictionary([{
type: 'list',
o: { data: "" },
url: 'http://example/list'
}, {
type: 'details',
o: { data: "" }, // just to show we can nest objects
url: 'http://example/{0}/details'
}], x => x.type);
dictionary.details.url // ok
现在,这样做的缺点是将为所有属性推断文字类型,例如包括url
(以及任何其他string
或number
属性)。这可能会让人分心。
答案 1 :(得分:0)
键入脚本(名称中的提示)。如果您正在寻找可以处理此问题的返回类型,也许您应该创建自己的Dictionary<T>
类型,然后在toDictionary
函数中返回它。我认为这是使智能感知以您喜欢的方式工作的唯一方法。