тип карты объекта возвращаемого типа - PullRequest
1 голос
/ 11 апреля 2019

Я сталкиваюсь с некоторым поведением, которое кажется мне немного странным.

В следующем примере у меня есть две функции, которые принимают объект в качестве ввода и возвращают объект с теми же ключами, но разными значениями. При использовании useForm1 я получаю ожидаемый результат. Я могу получить доступ к ключам свойств объекта ввода, и он также имеет правильное значение (Field).

Однако при использовании useForm2 (который использует Form<T> вместо встроенного { [P in keyof T]: Field } и на первый взгляд кажется, что он на самом деле одинаков), я также получаю объект, имеющий ключи входного объекта, к сожалению значения имеют тип Field, а не простой объект (он же {} без каких-либо свойств.).

Кто-нибудь может объяснить, почему эти два метода дают разные результаты, и как я могу скорректировать определения для useForm2?

type FormConfig<T> = {
  [P in keyof T]: {
    required?: boolean;
    validator?: (input: string) => void | Promise<void>;
    type: string;
  }
};

type Field = {
  required?: boolean;
  name: string;
  type: string;
  value: string;
};

type Form<T> = { [P in keyof T]: Field };

export const useForm1 = <T extends Object>(
  config: FormConfig<T>
): { [P in keyof T]: Field } => {
  // do some logic
};

export const useForm2 = <T extends Object>(config: FormConfig<T>): Form<T> => {
  // do some logic
};

const test1 = useForm1({
  login: {
    type: "text"
  }
});

const test2 = useForm2({
  login: {
    type: "text"
  }
});

1 Ответ

0 голосов
/ 11 апреля 2019

Object является очень общим типом и почти никогда не должен использоваться в TypeScript.В этом случае вы ожидаете, что в качестве входных данных будет использоваться карта ключ-значение, а возвращенная обработанная, поэтому этот тип следует указывать во всех ограничениях:

type Form<T extends Record<string, any>> = { [P in keyof T]: Field };

export const useForm1 = <T extends Record<string, any>>(
  config: FormConfig<T>
): { [P in keyof T]: Field } => {
  // do some logic
  return null as any
};

export const useForm2 = <T extends Record<string, any>>(config: FormConfig<T>): Form<T> => {
  // do some logic
};

test2.login.required // works
...