Машинописный текст не определяет тип значения ключа

что не так с тем, как я определяю этот тип

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> не связывает конкретный ключ с определенным значением. Если вы сделаете вывод Record, вы смешаете значения вместе. Вам нужен не infer вообще, а тип распределительного объекта, как показано в этой ссылке на игровую площадку. Это полностью решает вопрос? Если да, то я напишу ответ; если нет, то что мне не хватает?
jcalz 24.04.2024 21:08

🤯 спасибо большое, это именно то, что я хотел, я все делал неправильно

azzmi 24.04.2024 21:15
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
1
2
66
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Тип утилиты 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.

milad shirian 24.04.2024 23:24

Я нигде не вижу никаких «выводов». Покажите мне, что вы имеете в виду, на реальном коде.

jcalz 24.04.2024 23:46

Написанный вами формат приведет к тому, что 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 }
    }
};

Другие вопросы по теме