【问题标题】:How assign a value type to a generic key type of an object in typescript?如何在打字稿中将值类型分配给对象的通用键类型?
【发布时间】:2021-12-08 08:39:47
【问题描述】:

我正在尝试编写一个函数来合并,并将已排序的数组排序为一个排序数组。它接受对象数组的数组,以及一个要比较的键,这将是比较的基础。我需要确保提供的键的值始终是数字。

这是我目前的情况:

const sortMerge = <
  A extends Array<I>,
  K extends keyof A[number],
  I = A[number] & {
    [key in K]: number;
  },
>(
  arrays: A[],
  key: K,
  sortMethod = SortMethod.asc,
) => {
  const indexesOfArrays = arrays.map(() => 0);

  const mergedSorted = [];

  while (arrays.some((array, i) => array.length > indexesOfArrays[i])) {
    const currentItemsOfArrays = arrays.map(
      (array, arrayIndex) => array[indexesOfArrays[arrayIndex]],
    );
    const comparison = currentItemsOfArrays.map((item) =>
      item ? item[key] : (sortMethod === SortMethod.asc ? Infinity : -Infinity),
    );

    const nextArrayIndex = comparison.indexOf(
      Math[sortMethod === SortMethod.asc ? 'min' : 'max'](...comparison),
    );
    const nextItem = currentItemsOfArrays[nextArrayIndex];

    mergedSorted.push(nextItem);
    indexesOfArrays[nextArrayIndex]++;
  }
  return mergedSorted;
};

一切都很好,但它不能将I[K] 识别为number,但这就是我试图将KI 定义为泛型的原因。

我做错了什么?

预期的错误/类型:

const missingKey = [ { a: 1 } ];
const valid = [ { a: 2, b: 3 } ];
const anotherValid = [ { c: 3, b: 4 } ];

sortMerge([missingKey, valid], 'b') // missingKey[number] is missing property 'b';
sortMerge([valid, anotherValid], 'b') // expected return type: ({ a: number, b: number } | { c: number, b: number })[]

【问题讨论】:

  • 请提供有关通用约束的更多信息。你期望成为AKI

标签: arrays typescript types type-inference typescript-generics


【解决方案1】:

我稍微改变了通用约束:

enum SortMethod {
  asc = 'asc',
}
const sortMerge = <
  Key extends PropertyKey,
  Elem1 extends Record<Key, number>,
  Elem2 extends Record<Key, number>,

  Arr1 extends Elem1[],
  Arr2 extends Elem2[],
  Arrays extends [Arr1, Arr2]
>(
  arrays: [...Arrays],
  key: Key,
  sortMethod = SortMethod.asc,
): (Arrays[number][number])[] => {
  const indexesOfArrays = arrays.map(() => 0);

  const mergedSorted = [];

  while (arrays.some((array, i) => array.length > indexesOfArrays[i])) {
    const currentItemsOfArrays = arrays.map(
      (array, arrayIndex) => array[indexesOfArrays[arrayIndex]],
    );
    const comparison = currentItemsOfArrays.map((item) =>
      item ? item[key] : (sortMethod === SortMethod.asc ? Infinity : -Infinity),
    );

    const nextArrayIndex = comparison.indexOf(
      Math[sortMethod === SortMethod.asc ? 'min' : 'max'](...comparison),
    );
    const nextItem = currentItemsOfArrays[nextArrayIndex];

    mergedSorted.push(nextItem);
    indexesOfArrays[nextArrayIndex]++;
  }
  return mergedSorted;
}

const missingKey = [{ a: 1 }];
const valid = [{ a: 2, b: 3 }];
const anotherValid = [{ c: 3, b: 4 }];

sortMerge([missingKey, valid], 'b') // missingKey[number] is missing property 'b';
const x = sortMerge([valid, anotherValid], 'b')

Playground

如果要推断嵌套对象或数组中对象的键,则应从底部开始。

Key - 推断出的对象属性

Elem - 推断出的对象,其中键为 Key

Arr - Elem的推断数组

Arrays - Arr的推断数组

您可能已经注意到,我从推断 prop 的底层开始,并完成了顶层参数的推断。

如果你对函数参数的类型推断感兴趣,可以查看我的article

【讨论】:

  • 它确实有效,但它不能保留数组中元素的正确类型。它认为每个元素都是一个带有Key 的对象,其值为number。我希望它保留原始类型,只需确保提供的key 存在于每个对象上,并且它是number
  • 请提供有效和无效的方案
  • 请查看更新后的问题,如果需要更多信息,请告诉我。
  • @GergőHorváth 我更新了。
  • 其实`Arrays extends Arr[], Arr extends Elem[], Key extends PropertyKey, Elem extends Record = Arrays[number][number],`解决了问题,接受任何数组的数量,并正确保留类型。
猜你喜欢
  • 2020-06-29
  • 2019-06-08
  • 2021-10-11
  • 2022-08-18
  • 2018-05-06
  • 2020-06-29
  • 1970-01-01
  • 2017-03-31
  • 2023-03-12
相关资源
最近更新 更多