Задать тип значения generi c для объекта без указания типа ключа - PullRequest
0 голосов
/ 21 апреля 2020

У меня есть такая структура данных:

const endpoints = {
  async Login: (params) => { ... }
  async Register: (params) => { ... }
}

Теперь я хочу указать, что каждый элемент в этом объекте должен принимать объект params и возвращать обещание.

Я могу сделать что-то вроде это:

interface EndpointMap {
  [endpointName: string]: (
    params: Record<string, any>
  ) => Promise<any>;
}

Это хорошо работает. Но в этом есть и обратная сторона.

Если я сделаю что-нибудь еще, например, endpoint : keyof typeof endpoints, результат будет только string. Если бы я удалил интерфейс EndpointMap, я бы получил String Union всех ключей объекта endpoint. Гораздо лучше!

Есть ли способ получить лучшее из обоих миров?

Спасибо!

Ответы [ 2 ]

1 голос
/ 21 апреля 2020

Этого можно добиться, создав конечные точки с помощью функции идентификации:

interface EndpointMap {
  [endpointName: string]: (
    params: Record<string, any>
  ) => Promise<any>;
}

const createEndpoints = <TMap extends EndpointMap>(map: TMap) => map;

const endpoints = createEndpoints({
  login: async (params) => ({}),
  register: async (params) => ({})
});

/*
  type of 'endpoints' variable is: 
  {
      login: (params: Record<string, any>) => Promise<{}>;
      register: (params: Record<string, any>) => Promise<{}>;
  }
*/

Мы объявили функцию идентификации с EndpointMap ограничением для параметра типа generi c, поэтому машинопись будет убедитесь, что переданный параметр имеет соответствующую структуру. Кроме того, будет выведен тип параметра и допустимый тип ключей не будет расширен до string, поэтому:

type Keys = keyof typeof endpoints; // will be "login" | "register"

Детская площадка

1 голос
/ 21 апреля 2020

Один из способов добиться этого - вместо предоставления ключей в виде строки типа определить ключи в типе EndpointMap:

type EndpointMap = {
    [key in 'Login' | 'Register']: (
        params: any
    ) => Promise<any>
}

const endpoints: EndpointMap = {
    Login: (params) => { ... },
    Register: (params) => {...  }
}

// Valid
const oneKey: keyof typeof endpoints = 'Login'

// Type '"Random"' is not assignable to type '"Login" | "Register"'
const otherKey: keyof typeof endpoints = 'Random'
...