Проблемы с объединениями типов массивов

Вот несколько типов, которые я использую (упрощено для этого разговора):

export interface NodeId { readonly _nodeId: string }
export interface CellId { readonly _cellId: string }

export type Call = CodeCall | DefinitionCall

export interface CodeCall {
  readonly inputs: Array<{
    readonly outside: NodeId,
    readonly inside: string,
  }>,
}

export interface DefinitionCall {
  readonly inputs: Array<{
    readonly outside: NodeId,
    readonly inside: CellId,
  }>,
}

Ключевой момент: CodeCall и DefinitionCall каждый содержат массив «входов» с перекрывающимися, но разными определениями того, что такое вход.

Вот полезная функция для моего приложения:

export function doesCallUseNode1(call: Call, nodeId: NodeId): boolean {
  for (let input of call.inputs) {
    if (input.outside === nodeId) {
      return true;
    }
  }
  return false;
}

Это работает! Но, черт возьми, было бы неплохо использовать служебную функцию для поиска. Вот сигнатура полезной функции, которая мне нравится:

declare function findWith<T, K extends keyof T>(arr: T[], key: K, value: T[K]): boolean;

Но если я попытаюсь использовать это так,

export function doesCallUseNode2(call: Call, nodeId: NodeId): boolean {
  return findWith(call.inputs, "outside", nodeId)
}

Я получаю ошибку! В частности, это ошибка:

Argument of type '{ readonly outside: NodeId; readonly inside: string; }[] | { readonly outside: NodeId; readonly inside: CellId; }[]' is not assignable to parameter of type '{ readonly outside: NodeId; readonly inside: string; }[]'.

Мой анализ: call.inputs имеет тип {readonly outside: NodeId; readonly inside: string;}[] | {readonly outside: NodeId; readonly inside: CellId;}[]. findWith можно вызвать одним из следующих способов:

  • Т = {readonly outside: NodeId; readonly inside: string;}, К = 'outside'
  • Т = {readonly outside: NodeId; readonly inside: CellId;}, К = 'outside'

Но это не может быть вызвано с T = их объединением. Я думаю, это разумно - TypeScript не знает, что я использую массивы в контексте, в котором это должно иметь смысл.

Я застрял, пытаясь понять, как набрать findWith, чтобы это работало. Любые идеи? (Заранее благодарю за любую помощь!)


Обновлять: Спасибо Мэтту за полезный ответ ниже. Просто для справки в будущем: я реализовал это следующим образом (используя lodash) ...

export function findWith<T>(arr: Array<T>, key: keyof T, value: T[keyof T]): T | undefined {
  return _.find(arr, (o) => _.isEqual(o[key], value))
}

export function hasWith<K extends keyof any, V>(arr: {[key in K]: V}[], key: K, value: V): boolean {
  return !!findWith(arr, key, value)
}

Я рад, что hasWith можно реализовать (желаемым гибким способом), вызвав более строгий findWith, который содержит больше информации о типе для более строгого использования.

Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
0
283
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуй это:

declare function findWith<K extends keyof any, V>(arr: {[P in K]: V}[], key: K, value: V): boolean;

Затем вместо того, чтобы пытаться сопоставить T[] с {readonly outside: NodeId; readonly inside: string;}[] | {readonly outside: NodeId; readonly inside: CellId;}[] и получить два противоречивых вывода для T, вам просто нужно, чтобы в массиве был ключ, который вы ищете, что он делает для обоих случаев объединения.

Огромное спасибо! Я подумал о чем-то в этом роде, но пропустил обозначение «[P in K]». Отлично.

joshuahhh 10.09.2018 23:17

Другие вопросы по теме