字典功能的正确返回类型

时间:2019-01-08 09:29:42

标签: typescript

我有这个简单的功能:

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.listdictionary.details存在。

这有可能吗?我愿意更改此实现代码中的任何内容。所有数据都在构建时可用,即是静态的硬编码数据。

2 个答案:

答案 0 :(得分:2)

第一个问题是让编译器为可能会最终用作字典键的属性推断文字类型。如果将文字分配给扩展了可以缩小为文字的类型的通用类型参数的位置,则编译器将推断文字类型。

因此,在本例中,如果使用此约束,则将获得typeT 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(以及任何其他stringnumber属性)。这可能会让人分心。

答案 1 :(得分:0)

键入脚本(名称中的提示)。如果您正在寻找可以处理此问题的返回类型,也许您应该创建自己的Dictionary<T>类型,然后在toDictionary函数中返回它。我认为这是使智能感知以您喜欢的方式工作的唯一方法。