типа охранники и удлинители типа штуцера? - PullRequest
0 голосов
/ 06 мая 2020

У меня есть массив объектов, каждый из которых расширяет {x: method} или {y: method}, и я хочу попытаться разделить их. Я написал следующее

export const refresh = <
  N extends HasRefresh | HasRefreshWithFoo,
  RefreshWithFoo extends HasRefreshWithFoo,
  RefreshNormal extends HasRefresh
>(
  ns: N[],
  foos: Foo[]
) => {
  const refreshWithFoo: RefreshWithFoo = ns.filter((n): n is RefreshWithFoo  =>
    n.x !== undefined
  ) 
}

Но я получаю сообщение об ошибке

A type predicate's type must be assignable to its parameter's type.
  Type 'RefreshNormal' is not assignable to type 'N'.

Учитывая массив объектов, содержащих элементы, расширяющие HasRefreshWithFoo или расширяющие HasRefre sh, как я могу разделите массив объединением, чтобы у меня был один массив только с RefreshNormal и один только с RefreshWithFoo?

1 Ответ

1 голос
/ 06 мая 2020

Вы можете сузить ошибку компилятора, сделав еще одну абстракцию общих типов c.
Вторая абстракция будет отвечать за фильтрацию массива по заданному типу.

const filterByType = <T>(arr: any[], key: keyof T): T[] =>
    arr.filter(e => (<T>e)[key]) as T[];

После Руководство по типу скрипта о том, как ввести охрану экземпляра , мы вынуждены указать, какой ключ проверять, было ли преобразование выполнено эффективно (уникальный ключ в типе, по которому мы фильтруем).

Итак , теперь мы можем фильтровать в нашей функции по RefreshWithFoo

export const refresh = <
  N extends HasRefresh | HasRefreshWithFoo,
  RefreshWithFoo extends HasRefreshWithFoo,
  RefreshNormal extends HasRefresh
>(
    ns: N[], 
    foos: Foo[]
) => {
    const refreshWithFoo: RefreshWithFoo[] = filterByType<RefreshWithFoo>(ns, `x`);
}

Без каких-либо жалоб компилятора.
Ну, я использую по умолчанию tsconfig , я полагаю, это не будет жаловаться с любой другой конфигурацией компилятора. Если да, дайте мне знать.

Edit
В некоторых случаях, например, при пересечении типов, вам потребуется более одного ключа для проверки. Вы можете просто расширить метод, ожидая массив ключей params и проверив их все, например, так

const filterByType = <T>(arr: any[], ...keys: (keyof T)[]): T[] =>
    arr.filter(e => keys.every(k => (<T>e)[k])) as T[];

Надеюсь, это поможет.

...