【问题标题】:Trying to use the spread operator with TypeScript and Object.assign尝试将扩展运算符与 TypeScript 和 Object.assign 一起使用
【发布时间】:2019-08-21 11:58:03
【问题描述】:

我正在尝试将一些映射值分配给这样的对象:

const sampleStrings = ['foo', 'bar', 'baz'];
const sampleValues = sampleStrings.map(value => ({
  [value]: {
    name: 'bob',
  },
}));
const result = Object.assign(...sampleValues);

console.log(result)

但是,我收到以下错误消息:

TS2557:预期至少有 1 个参数,但得到了 0 个或更多。

我知道我应该做类似的事情

interface Foo {
  [x: string]: {
    name: string;
  };
}

const sampleStrings = ['foo', 'bar', 'baz'];
const sampleValues = sampleStrings.map(value => ({
  [value]: {
    name: 'bob',
  },
}));
const result = Object.assign(...sampleValues);

但我无法完全弄清楚我的Foo 接口应该如何配置。另外,如果我不知道我的sampleStrings 数组的长度会怎样,那我该如何解决这个问题呢?

【问题讨论】:

  • 因为Array.prototype.map 返回类型是T[] 并且不可能从中推断出它的大小至少为1。

标签: typescript


【解决方案1】:

所有编译器实际上都知道sampleValues 的类型是Array<Record<string, {name: string}>>。这样的数组类型可以有任意数量的元素,包括零,所以你不能将它传播到一个至少有一个参数的函数中而不抱怨。

处理这个问题的最简单方法可能是使用type assertion 告诉编译器sampleValues 是一个比它可以推断的更具体的类型。为避免该错误,您只需选择包含至少一个元素的 tuple 类型,但您可以更进一步,更详细:

const sampleValues = sampleStrings.map(value => ({
  [value]: {
    name: "bob"
  }
})) as [
  { foo: { name: string } },
  { bar: { name: string } },
  { baz: { name: string } }
];

这里我们说sampleValue 将是一个正好包含三个对象的元组,每个对象都有一个来自foobarbaz 的已知键,以及一个{name: string} 类型的值。这将允许您传播到Object.assign()

const result = Object.assign(...sampleValues); // okay
// const result: {foo: {name: string}} & {bar: {name: string}} & {baz: {name: string}}

并且result 的类型已知是类似于{foo: {name: string}, bar: {name: string}, baz: {name: string}} 的交集类型。

我认为这是我建议的解决方案。


您可以尝试告诉编译器 sampleStrings 是一个 n 元组(例如,使用 const assertion),并且在 n 元组上的映射会产生另一个 n-像这样的元组(例如,使用declaration merging):

interface ReadonlyArray<T> {
  map<U>(cb: (val: T) => U): { [K in keyof this]: U };
}

const sampleStrings = ["foo", "bar", "baz"] as const;

const sampleValues = sampleStrings.map(value => ({
  [value]: {
    name: "bob"
  }
}));
const result = Object.assign(...sampleValues);
/* const result: {
    [x: string]: {
        name: string;
    };
} */

这将防止 Object.assign() 错误,但是当你完成后,你仍然会得到一个相当弱类型的对象 result... 并且你投入更多的工作试图让编译器 infer 更好的类型,代码变得越不清晰。所以我可能会建议不要试图让编译器更聪明地了解这里发生的事情,而是使用一些精心挑选的类型断言来使编译器的工作更容易而不是更难。在我看来,它不是类型安全的(因为你的断言总是错误的),但它是更简洁的代码。


好的,希望对您有所帮助。祝你好运!

Link to code

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-17
    • 2020-10-21
    • 2019-01-17
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    • 2022-09-23
    • 2020-01-26
    相关资源
    最近更新 更多