Ограничить общий тип ключа на основе типа поиска в TypeScript

Я работаю над функцией, которая принимает два параметра типа, T и K. T расширяет тип Record, а K является ключом первого типа. Есть ли способ ограничить тип ключа на основе его типа поиска (T[K]) в T?

У меня есть следующие типы:

type FormValue = string | number | boolean | null;

type FormValues = Record<string, FormValue>;

и следующая функция:

function numericFormHelperFunc<T extends FormValues, K extends keyof T>(key: K, formValues: T) {}

Есть ли способ ограничить, какие клавиши можно использовать для этой функции, чтобы были разрешены только клавиши в formValues, которые имеют типы поиска, скажем, number? В основном способ утверждать, что T[K] extends number.

Например, если у меня есть этот пример типа формы:

type MyFormValues = {
    name: string;
    age: number;
    numPets: number;
}

Могу ли я добавить ограничение типа к numericFormHelperFunc, чтобы можно было использовать только ключи "age" и "numPets"?

Я ищу статический способ сделать это, чтобы получать предупреждения редактора о попытке использовать numericFormHelperFunc("name", myFormValues). Также хотелось бы, чтобы машинописный текст знал, что значение при поиске key в formValues имеет определенный тип, а не просто T[K] (например, чтобы числовые методы и операторы можно было использовать без утверждений типа).

Это нормально для вас typescriptlang.org/play?ts=3.9.7#code/… ?

captain-yossarian from Ukraine 10.12.2020 22: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 для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
1
632
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вот решение:

type FormValue = string | number | boolean | null;

type FormValues = Record<string, FormValue>;

type MyFormValues = {
  name: string;
  age: number;
  numPets: number;
}

/**
 * Takes two arguments,
 * T - indexed type
 * Allowed - allowed types
 * 
 * Iterates through all properties and check
 * if property extends allowed value
 */
type Filter<T, Allowed> = {
  [P in keyof T]: T[P] extends Allowed ? P : never
}[keyof T]

function numericFormHelperFunc<T extends FormValues>(key: Filter<MyFormValues, number>, formValues: T) { }

numericFormHelperFunc('age', {'sdf':'sdf'}) // ok
numericFormHelperFunc('numPets', {'sdf':'sdf'}) // ok
numericFormHelperFunc('hello', {'sdf':'sdf'}) // error
numericFormHelperFunc('2', {'sdf':'sdf'}) // error
numericFormHelperFunc('name', {'sdf':'sdf'}) // error

Для понимания, причина, по которой это работает, заключается в том, что AnyType | never === AnyType.

y2bd 10.12.2020 22:25

Это плюс строка [keyof T] в конце, да.

y2bd 10.12.2020 22:36

Определенно касается основного вопроса моего вопроса, спасибо. Для этого может потребоваться открыть отдельный вопрос, но есть ли способ сообщить редактору о базовом типе при использовании типа поиска? В этом случае было бы неплохо иметь возможность обрабатывать значение для данного ключа как number без необходимости делать какие-либо утверждения типа. Это возможно?

Henry Woody 10.12.2020 23:28

Кажется, это возможно, если использовать фактический тип FormValues, но не с T extends FormValues (по крайней мере, без дополнительной обработки).

Henry Woody 10.12.2020 23:37

Не уверен, что это возможно

captain-yossarian from Ukraine 11.12.2020 07:46

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