что не так с тем, как я определяю этот тип
type Payload<Es> = {
trigger:
Es extends Record<infer K, infer V>
? { key: K, data: V } : never
}
type Evs = {
"item.1": { ok: "Y", code: number }
"item.2": 1 | 0
}
const payload: Payload<Evs> = {
trigger: {
key: "item.1",
data: 1
}
}
payload.trigger.data
не получается так, как я ожидаю
ожидал
{ ok: "Y", code: number }
что я получаю
0 | { ok: "Y", code: number } | 1
🤯 спасибо большое, это именно то, что я хотел, я все делал неправильно
Тип утилиты Record<K, V> — это тип, соответствующий объектам с ключами свойств типа K
и значениями свойств типа V
. Но конкретные ключи не связаны с конкретными значениями. Если вы начнете с {a: string, b: number}
и попытаетесь вывести из него a Record<K, V>
, вы получите Record<"a" | "b", string | number>
. Это тот же тип, который вы получили бы от {a: number, b: string}
. Таким образом, вы вообще не хотите делать здесь вывод о Record
, если только вы не хотите смешать все свойства вместе.
Вместо этого вам действительно нужно просто сопоставить тип, перебрать каждый ключ K
и создать соответствующий тип объекта, а затем индексировать сопоставленный тип, чтобы получить объединение свойств. То есть вам нужен дистрибутивный тип объекта (как это описано в microsoft/TypeScript#47109):
type Payload<E> = {
trigger: { [K in keyof E]: { key: K, data: E[K] } }[keyof E]
}
Вы можете убедиться, что это дает вам то, что вы ищете:
type Evs = {
"item.1": { ok: "Y", code: number }
"item.2": 1 | 0
}
type PEvs = Payload<Evs>;
/* type PEvs = {
trigger: {
key: "item.1";
data: {
ok: "Y";
code: number;
};
} | {
key: "item.2";
data: 0 | 1;
};
} */
const payload: Payload<Evs> = {
trigger: {
key: "item.1",
data: 1 // error!
}
}
Детская площадка, ссылка на код
Привет, в вашем коде машинописный текст будет определять свойство ok как строку, а не Y.
Я нигде не вижу никаких «выводов». Покажите мне, что вы имеете в виду, на реальном коде.
Написанный вами формат приведет к тому, что TypeScript выведет объединение всех возможных значений для Record, что сделает невозможным вывод TypeScript, соответствующий ожидаемому типу. Если только вы не предоставите другой универсальный тип для его типа полезных данных, который указывает, какой тип значения вы хотите для данных на основе специального ключа. Так:
type Payload<Es, P extends keyof Es = keyof Es> = {
trigger: Es extends Record<infer K, infer V> ? { key: K, data: Es[P] } : never
}
type Evs = {
"item.1": { ok: "Y", code: number };
"item.2": 1 | 0;
};
const payload: Payload<Evs, 'item.1'> = {
trigger: {
key: "item.2",
data: { ok: "Y", code: 123 } // TypeScript will infer { ok: "Y", code: number }
}
};
Record<K, V>
не связывает конкретный ключ с определенным значением. Если вы сделаете выводRecord
, вы смешаете значения вместе. Вам нужен неinfer
вообще, а тип распределительного объекта, как показано в этой ссылке на игровую площадку. Это полностью решает вопрос? Если да, то я напишу ответ; если нет, то что мне не хватает?