Тип — работа. Но при этом теряется подсказка для правильного варианта... Почему? или Как улучшить?

Это реальный (упрощенный) пример некоторой функции lab

const lab = <
  T extends Something,
  K extends keyof T
>(k: T[K] extends (...args: any[]) => any ? K : never) => {
  return ({} as T)[k];
}

const test = lab<Something, 'fn'>('fn')

type Something = {
  str: string,
  num: number
  bool: boolean,
  fn: (a: number, b: number) => number,
}

Это работает так, как ожидалось. Но на скринах ниже я показываю то, что тоже хочу и не понимаю, почему это невозможно.

Ниже несколько скринов, чтобы убедиться, что в целом тип работает.

разрешить str в общем заполнителе в качестве ключа Something, но ошибка с аргументом... так что это работает

событие, если аргумент становится str также ошибка... так что работает

разрешите fn и дайте чаевые в качестве аргумента... хорошо!

да, это только один правильный вариант и никаких ошибок! работает

Но почему он не может дать мне чаевые fn сразу? Или хотя бы любую из клавиш Something, то есть str, num...?

Скриншоты IDE здесь, к сожалению, не уместны. Пожалуйста, замените изображения кода/журналов/ошибок/подсказок текстовыми версиями.

jcalz 20.04.2024 23:10

(см. предыдущий комментарий). Как только вы это исправите: TS просто не создает списки завершения для аргументов универсального типа при вызове универсальной функции. Эта ссылка на игровую площадку показывает то, что я считаю настоящим минимально воспроизводимым примером здесь. Я бы сказал, что если вас это действительно волнует, вы можете подать запрос на функцию TS. Или, может быть, вы можете выполнить рефакторинг для использования каррирования, как вот так. Это полностью решает вопрос? Если да, то я напишу ответ с объяснением; если нет, то что мне не хватает?

jcalz 20.04.2024 23:32

@jcalz, Спасибо за совет! Кроме того, ваш пример более крутой, потому что он еще проще, но да — меня интересует why typescript don't tip me correct answers if it can say that another ones are incorrect?. и ваш ответ: TS just doesn't seem to do completion lists for generic type arguments when calling a generic function Звучит правильно... но для меня всё равно немного запутанно) P.S. может быть позже я постараюсь упростить и свой вопрос, изображения и т. д. В любом случае спасибо!)

nik-kita 21.04.2024 00:29

Думаю, напишу ответ, как только появится возможность

jcalz 21.04.2024 01:27
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой 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
4
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы ищете IntelliSense, чтобы автоматически предлагать список завершения для аргумента общего типа для параметра типа K при вызове функции lab(). Но поддержка IntelliSense в TypeScript не обеспечивает таких дополнений. Вы можете показать это на минимальном примере, например:

const f = <K extends "x" | "y">() => 0;
f<"x">() // okay
f<"">()
// ^ abc "A"
// ^ abc "a"
// ^ abc "All"
// ^ abc "all"
// ...

Здесь IntelliSense должно быть невероятно легко рекомендовать либо "x", либо "y", но вместо этого вы получаете полный список всех строковых литералов, о которых знает TypeScript.

Существует давний запрос на открытие функции по адресу microsoft/TypeScript#28662 с просьбой об этом. Если вы хотите увидеть, как это произойдет, возможно, вам захочется пойти туда и поставить 👍. Но до тех пор, пока оно не будет реализовано, вам придется отказаться от него или обойти его.


Если вы готовы использовать значения вместо типов, вы можете каррировать свою функцию, чтобы указать аргумент типа для T вручную, а затем возвращаемая функция будет ограничивать K только теми типами, которые вы хотите поддерживать, и тогда вы не не указываем вручную K; вместо этого вы просто вызываете функцию со значением типа K и получаете список завершения IntelliSense для аргумента функции:

const lab = <T extends Something>() =>
    <K extends { [P in keyof T]:
        T[P] extends (...args: any) => any ? P : never
    }[keyof T]>(
        k: K
    ) => { return ({} as T)[k]; }


const test = lab<Something>()("") // <--
//                            ^🔧 fn

Здесь вы указали Something, а затем получаете fn в качестве предлагаемого ввода для возвращаемой функции.

Каррирование необходимо только в том случае, если вам вообще требуется K быть универсальным; вы можете не:

const lab = <T extends Something>(k: { [P in keyof T]:
    T[P] extends (...args: any) => any ? P : never
}[keyof T]) => { return ({} as T)[k]; }

const test = lab<Something>("") // <--
//                          ^🔧 fn

Но это небольшое отступление от ответа на заданный вопрос: тот тип списка завершения, который вам нужен, невозможен без microsoft/TypeScript#28662.

Ссылка на код детской площадки

Спасибо большое за такой развернутый ответ, @jcalz! Для меня это очень полезно как с точки зрения машинописи (даже далеко за рамками вопроса), так и в целом как пример хорошего дизайна общения, размещения вопросов и ответов и т. д. Я действительно вдохновлен, еще раз спасибо!)

nik-kita 21.04.2024 14:02

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

Похожие вопросы

Net::ERR_CONNECTION_REFUSED и неперехваченная ошибка при использовании Axios с использованием TanStack-Query useMutation (asyncMutation)
Как отключить проверку сборки angular cling в определенном каталоге?
Использование сокращения() изменяет исходный массив в документации JavaScript, утверждающей обратное
Реализация перехода от бегущей линии вперед (CLA) к шаблону поиска области задач в Leaflet.js
Как отобразить изображение по умолчанию, только если в этом приложении фильмов Angular 16 нет постера фильма?
Внедрение зависимостей NestJs в конструктор не определено для поставщика на основе классов, но работает с поставщиком токенов
Определение типа для массива компонентов React с их реквизитами
Машинописный скрипт Chakra ui обеспечивает aria-label для кнопки со значком – как отключить
Как назначить тип функции, которая имеет разные/дополнительные аргументы в машинописном тексте
Typescript — создание подмножества дискриминируемого объединения как дискриминируемого объединения