TypeScript: почему общие параметры принимают неправильные аргументы?

У меня есть функция с определенными типами аргументов. Аргументы: key, который является ключом указанного интерфейса IBook, и value, который должен иметь тип, соответствующий этому конкретному ключу в интерфейсе. т.е. если key === 'id', то единственным допустимым типом для value должен быть number.

Проблема возникает, когда я хочу создать другую функцию, чтобы просто передавать аргументы из события onChange в первое. Чтобы избежать повторного объявления аргументов функции, я использовал Parameters generic, но, похоже, он ведет себя неправильно. Проверьте использование ниже.

interface IBook {
  id: number;
  title: string;
  isPromoted?: boolean;
}

export const editBook = <K extends keyof Required<IBook>>(
  key: K,
  value: Required<IBook>[K],
) => ({
  type: 'EDIT_BOOK',
  payload: { key, value },
});

const onChange = (...args: Parameters<typeof editBook>) => {
  dispatch(editBook(...args));
};

editBook('id', 'some string'); // string not accepted here, shows error
onChange('id', 'some string'); // no error here

editBook('id', true); // boolean not accepted here, shows error
onChange('id', true); // no error here

Если я использую исходную функцию editBook, то value набирается правильно — только та, которая соответствует типу key. Если я использую другой, отображается ошибка. Однако, если я использую функцию-оболочку onChange, то любой тип, существующий в IBook, принимается в качестве аргумента value.

Как я могу это исправить?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Когда вы используете Parameters, вы не захватываете параметры типа исходной функции, typescript просто использует ограничение, где он находит любую ссылку на параметр типа, поэтому подпись onChange на самом деле будет просто:

(key: keyof IBook, value: Required<IBook>[keyof IBook]) => void

что получится:

(key: "id" | "title" | "isPromoted", value: string | number | boolean) => void

разрешение недействительных вызовов.

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

function pipe<A extends any[], B, C>(ab: (...args: A) => B, bc: (b: B) => C): (...args: A) => C {
    return (...args: A) => bc(ab(...args));
}

function dispatch<T extends { type: string }>(action: T): void {

}
const onChange = pipe(editBook, dispatch); // generic type parameter preserved

editBook('id', 'some string'); // string not accepted here, shows error
onChange('id', 'some string'); // error now

editBook('id', true); // boolean not accepted here, shows error
onChange('id', true); // error now

Спасибо за объяснение! Как жаль, что Parameters так не работает.

Chris Gaszynski 12.04.2019 15:20

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