TypeScriptの型の指定で困っています。以下のような toMap という関数でコンパイルを通すことができません。

const toMap = <T extends {}>(items: T[], key: keyof T) => {
    const map = {};
    items.forEach((item) => {
        map[item[key]] = item; // ここでエラー
    });
    return map;
}

const data = [
    { id: '1', value: { foo: 'bar' } },
    { id: '2', value: { hoge: 'piyo' } },
];

toMap(data, 'id'); // => { '1': { ... }, '2': { ... } }

<T extends {}>(items: T[], key: any): { [key: string]: T } とでも妥協すればいいのはわかるのですが、 any を使わずに解決したいと思っています。

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#example-2FunctionPropertyNames<T> を参考に type StringPropertyNames<T> = { [K in keyof T]: T[K] extends string ? K : never }[keyof T]; を定義し、 <T extends {}>(items: T[], key: StringPropertyNames<T>) としたのも駄目でした。