Generi c для функции охраны типа - PullRequest
0 голосов
/ 16 марта 2020

Я хотел бы создать функцию, которая фильтрует список двух типов в два отдельных списка уникального типа. Мне удалось создать его с жестко закодированными типами:

interface TypeA {
  kind: 'typeA';
}
interface TypeB {
  kind: 'typeB';
}
filterMixedList(mixedList$: Observable<(TypeA | TypeB)[]>): Observable<TypeA[]> {
  return mixedList$.pipe(
    map(items => items
      .filter((item): item is TypeA => item.kind === 'typeA')),
  );
}

Но есть ли способ создать generi c, чтобы избежать жесткого кодирования? Пожалуйста, помогите.

PS: вот минимальный воспроизводимый пример: stackblitz

1 Ответ

1 голос
/ 17 марта 2020

Один из способов сделать это обобщение c - передать функцию защиты типа. Это будет выглядеть так:

function typeFromMixedList<T, U extends T>(
  mixedList$: Observable<T[]>,
  guard: (item: T) => item is U
): Observable<U[]> {
  return mixedList$.pipe(map(items => items.filter(guard)));
}

Или, если вы знаете, что тип, который вы проверяете, является дискриминируемым объединением , вы можете передать дискриминантный ключ и значение для проверки:

function typeFromDiscriminatedUnionList<
  T,
  K extends keyof T,
  V extends (T[K]) & (string | number | undefined | null)
>(
  mixedList$: Observable<T[]>,
  key: K,
  val: V
): Observable<Extract<T, { [P in K]?: V }>[]> {
  return mixedList$.pipe(
    map(items =>
      items.filter(
        (item): item is Extract<T, { [P in K]?: V }> => item[key] === val
      )
    )
  );
}

Любой способ должен работать для вашего примера:

typeFromMixedList(of([a, b]), (x): x is TypeA => x.kind === "typeA").subscribe(
  v => (dataDivA.innerHTML = JSON.stringify(v))
);

typeFromDiscriminatedUnionList(of([a, b]), "kind", "typeB").subscribe(
  v => (dataDivB.innerHTML = JSON.stringify(v))
);

Хорошо, надеюсь, это поможет; удачи!

Stackblitz ссылка на код

...