Как динамически создать сопоставленный тип в TypeScript - PullRequest
0 голосов
/ 28 декабря 2018

Дано:

type Indexed<Key extends number, Value> {
    [key in Key]: Value
}

let objLiteral: Indexed<1 | 2, string> = {
    1: "one",
    2: "two",
}

Теперь я хочу динамически создать новый Indexed<1 | 2, {x: string}>.Эквивалентный JavaScript должен быть правильным, но он не компилируется:

let mappedObj: Indexed<1 | 2, {x: string}> =
    Object.keys(objLiteral).reduce((acc, cur) => {
        acc[cur] = {x: objLiteral[cur]}
        return acc
    }, {})

Теперь, он прекрасно работает, если я добавлю as Indexed<1 | 2, { x: string }> в его конец.Но это в основном просто говорит компилятору "поверь мне, это правильно".Есть ли способ сделать это, который не требует переопределения системы типов таким способом?

1 Ответ

0 голосов
/ 29 декабря 2018

Нет встроенной функции для этого, но вы можете создать вспомогательную функцию, которая имеет пару приведений внутри, но затем предоставит вам правильные типы для любого использования:

function mapObject<
    TObject extends {},
    TItem,
    TKey extends keyof TObject = keyof TObject
>(
    obj: TObject,
    callback: (value: TObject[TKey], key: TKey, obj: TObject) => TItem
): { [K in TKey]: TItem }
{
    const result = {} as { [K in TKey]: TItem }
    for (let key in obj) {
        const k = key as any as TKey
        if (obj.hasOwnProperty(key)) {
            result[k] = callback(obj[k], k, obj)
        }
    }
    return result;
}

let mappedObj = mapObject(objLiteral, x => ({ x }));
mappedObj[1].x; // has type "string" as expected
...