Ввод массива обобщенных c предполагаемых типов - PullRequest
2 голосов
/ 20 июня 2020

Я пытаюсь создать тип массива объектов. Первый и второй ключи этого объекта должны совпадать. Например:

[{ 
  key1: "hi",
  key2: "world"
},{
  key1: 1,
  key2: 2
},{
  key1: true,
  key2: false
}]

Это то, что я придумал, но это не совсем работает. У меня есть тип generi c для определения объекта в массиве. При вызове его для генерации типа массива возникает ошибка.

type ArrayItem<T> = {
  key1: T,
  key2: T
}

// This raises an error Generic Type ArrayItem requires 1 type argument
type Array = ArrayItem<T>[]

Как лучше всего ввести такой вложенный объект ( с поддержкой вывода типа )?

Ответы [ 2 ]

1 голос
/ 21 июня 2020

Если у вас нет конечного списка возможных типов для T в ArrayItem<T>, в TypeScript нет конкретного типа, соответствующего Array<ArrayItem<T>>. Чтобы представить такую ​​вещь как неуниверсальный тип c, потребуется что-то вроде экзистенциальные типы , которые TypeScript не поддерживает напрямую.

(Если вы do иметь конечный список, например ArrayItem<string> | ArrayItem<number> | ArrayItem<boolean>, тогда вы можете просто использовать объединение, как в другом ответе.)

Ближе всего к этому можно подойти в TypeScript как общий тип c, и Лучшее, что вы сделаете с точки зрения вывода и предупреждений компилятора, - это представить это как что-то вроде generi c constraint .

Один из способов сделать это - написать generi c вспомогательная функция asMyArray() принимает кортеж , и компилятор проверяет каждый элемент кортежа, чтобы убедиться, что он соответствует ограничению. Одна загвоздка в том, что {key1: "hi", key2: 2} соответствует ограничению, если вы разрешаете такие вещи, как string | number как T. Чтобы компилятор не принимал все пары типов, я попытаюсь сделать вывод T только из key1 (см. microsoft / TypeScript # 14829 , чтобы увидеть способы предотвращения вывода из определенного вывода site), а затем просто убедитесь, что key2 соответствует этому:

const asMyArray = <T extends readonly any[]>(
    x: { [K in keyof T]: { key1: T[K], key2: T[K] & {} } } | []) =>
    x as { [K in keyof T]: { key1: T[K], key2: T[K] } };

Параметр типа generi c T является кортежем, соответствующим значениям key1 для каждого элемента переданного - в массиве. Переданный массив x имеет сопоставленный кортеж типа . Бит & {} снижает приоритет вывода key2. Бит | [] просто побуждает компилятор вывести кортеж, а не массив (где он не сможет отличить разные элементы друг от друга). Давайте проверим это:

const myArray = asMyArray([{
    key1: "hi",
    key2: "world"
}, {
    key1: 1,
    key2: 2
}, {
    key1: true,
    key2: false
}])
// const asMyArray: <[string, number, boolean]>(...)

Вы можете видеть что T выводится как [string, number, boolean]. Это выполняется успешно, в то время как следующее, в котором T выводится таким же образом, терпит неудачу:

const badArray = asMyArray([{
    key1: "hi", key2: 123 // error!
    // -------> ~~~~
    // number not assignable to string
}, {
    key1: 1, key2: "world" // error!
    // ----> ~~~~
    // string not assignable to number
}, {
    key1: true, key2: false
}]);

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

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

0 голосов
/ 20 июня 2020

Работа с массивами может быть беспорядочной, даже при обычном вводе c. Это во многом зависит от того, как ваши элементы будут использоваться после инициализации массива. На основе ваших фрагментов я бы начал создавать интерфейсы для каждого «типа» записи в массиве, чтобы получить строгую типизацию для каждого отдельного набора свойств.

export interface FooItemType {
  key1: string,
  key2: string,
}


export interface BarItemType {
  key1: boolean,
  key2: boolean,
}

Затем вы можете создать новый тип, который отображает интерфейсы, которые вы определили ранее.

export type ItemType = BarItemType | FooItemType;

После этого вы можете объявить его как простой ItemType массив.

export myArr: ItemType[] = [{ 
  key1: "hi",
  key2: "world"
},{
  key1: 1,
  key2: 2
},{
  key1: true,
  key2: false
}]

Хотя этот подход строго типизирован, это может привести к некоторому ручному преобразованию после того, как вы получите элемент myArray[i] из массива. Иногда мы проектируем "типизацию" до того, как обдумываем ее использование в приложении, поэтому структура данных должна быть разработана с учетом ее в целом.

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