Как я могу ввести точечную нотацию для строки в Typescript - PullRequest
1 голос
/ 07 августа 2020

Я пытаюсь создать функциональный API, который выглядит так:

createRoute('customers.view', { customerId: 1 });  // returns `/customers/1`

Однако у меня проблемы с вводом первого аргумента. Вот что у меня есть на данный момент:

const uris = {
  customers: {
    view: '/customers/:customerId',
  },
  users: {
    list: '/users',
  }
};

const createRoute = (route: string, routeParams: { [key: string]: string }) => {
  /**
   * This will split 'customer.view' each on a variable
   */
  const [ resource, action ] = route.split('.');

  /**
   * HERE:  I'm getting this error:
   *  
   *   Element implicitly has an 'any' type because expression of type 'string' 
   *   can't be used to index type '{ customers: { view: string; } }'.
   *
   */
  const uri = uris[resource]?.[action]


  // ... rest of code to replace the route param...
};

Я понимаю, что означает ошибка. Сигнатура функции позволяет мне передавать любые string, но она должна быть ограничена действительными ключами объекта uri.

Более того, второе разделение строки зависит от первого (это все-таки вложенный объект).

Можно ли это набрать?

Ответы [ 3 ]

2 голосов
/ 07 августа 2020

Вы также можете сделать следующее:

createRoute(['customers', 'view'], {}); // compile
createRoute(['users', 'list'], {}); // compile
createRoute(['users', 'view'], {}); // DOESN'T compile: Type '["users", "view"]' is not assignable to type 'Route<ICustomerUri>'.
createRoute(['nota router'], {}); // DOESN'T compile: Type '"nota router"' is not assignable to type '"customers" | "users"'

Код:

interface ICustomerUri {
    customers: {
        view: string;
    };
}

interface IUsersUri {
    users: {
        list: string;
    };
}

type Route<T> = [keyof T, keyof T[keyof T]];

type Routers = Route<ICustomerUri> | Route<IUsersUri>;

interface IUris extends ICustomerUri, IUsersUri {}

const uris: IUris = {
    customers: {
        view: '/customers/:customerId',
    },
    users: {
        list: '/users',
    }
};

const createRoute = (route: Routers, routeParams: { [key: string]: string }) => {
    // your implementation
}

Ссылка на игровую площадку

1 голос
/ 07 августа 2020

Этот формат должен работать для вас:

const resource = route.split('.')[0] as keyof typeof uris;
const action = route.split('.')[1] as keyof typeof uris[typeof resource];

Playground Link

0 голосов
/ 08 августа 2020

Спасибо всем за ваш вклад. Подходы были либо слишком сложными, либо фактически не обеспечивали безопасность типов. Вместо этого я выбрал более простой:

const uris= {
  'customers.view': '/customers/:customerId',
  'users.list', '/users',
};

type Route = keyof typeof routePatterns;

const createRoute = (route: Route,  ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...