【问题标题】:Is there a type-safe way to reduce() a larger object into a new type in typescript?是否有一种类型安全的方法可以将较大的对象减少()为打字稿中的新类型?
【发布时间】:2020-10-14 12:39:55
【问题描述】:

我有一个表示数据库查询结果的数据结构,它是一个具有许多属性的对象,都是标量(在我的例子中,都是字符串或数字)。我想提取这些属性的一部分并填写一个具有定义形状的新对象。

const input: Record<string, string | number> = { name: 'Jane', age: 42, fav_pet: 'Dog', fav_col: 'Blue', fav_dest: 'Paris' };
const FAVS = ['pet', 'col', 'dest'] as const;
type FavsType = {
  pet: string;
  col: string;
  dest: string;
}

const output: FavsType = FAVS.reduce((acc, key) => ({ ...acc, [key]: input['fav' + key] }), {});
//    ~~~~~~
//    ^^^^^^ Type '{}' is missing the following properties from type 'FavsType': pet, col, dest

问题是,如果我使用reduce 方法来执行此操作,Typescript 无法确定 reduce 的返回值必须包含正确形状的对象。我也尝试过使用 Object.fromEntries(FAVS.map()) 得到类似的结果。

是否有任何类型安全的解决方案不涉及显式分配每个属性?

Playground Link

【问题讨论】:

  • reduce 的返回类型是从第二个参数推断出来的(在本例中为 {})或由 generic type 提供(例如 .reduce&lt;FavsType&gt;(...))。
  • 你可以使用类型断言const output: FavsType = FAVS.reduce((acc, key) =&gt; ({ ...acc, [key]: input['fav' + key] }), &lt;FavsType&gt;{});
  • 您也可以使用 keyof 操作使 const FAVS 类型安全,因为该数组仅包含 FavsType const FAVS: (keyof FavsType)[] = ['pet', 'col', 'dest'] 的键的值
  • @IAMTHEBEST 实际上产生比as const 更弱的类型,因为它允许突变。
  • @IAMTHEBEST 我以另一种方式查看关系 - 它是 FavsType 包含来自 FAVS 的所有条目。所以,对我来说,从另一个方向派生为映射类型似乎更合乎逻辑:type FavsType = { [key in typeof FAVS[number]]: string; }

标签: typescript types reduce


【解决方案1】:

是打字稿。当 Typescript 遇到 reduce 时,它​​必须声明它必须键入的新变量。

const output: FavsType = FAVS.reduce((acc, key) => ({
  ...acc,

  [key]: input[`fav${key}`],
}), ------> {} <------);

累加器被初始化为{},然后打字稿推断类型'{}'

从打字稿的角度来看,改变累加器不会改变它的类型。

你必须告诉打字稿

相信我,返回的类型是 FavsType

这就是断言的用武之地:

const output: FavsType = FAVS.reduce((acc, key) => ({
  ...acc,

  [key]: input[`fav${key}`],
}), {}) as FavsType;

理想情况下,打字稿应该看到对象的突变并推断出正确的 reduce 返回类型,但它还不是那么“聪明”。

【讨论】:

  • 未来 Typescript 可能会足够聪明,可以自己确定,但现在只需使用 const output: FavsType = FAVS.reduce((acc, key) =&gt; ({ ...acc, [key]: input['fav' + key] }), &lt;FavsType&gt;{});
  • 你的提议和我的不同之处在于,你在创建累加器时告诉 typescript 累加器值得 FavsType,这是错误的。另一方面,转换 reduce 的返回值是“正确的”,返回值确实与 FavsType 匹配。两者都有效,但我认为保持某种连贯性很重要
  • 我明白你的意思,我的回答初始化了累加器{},我告诉 Typescript 类型是 FavsType。然后编译器足够聪明地根据 reduce 的返回类型来确定类型,因为它返回累加器。有了你的答案,你首先进行操作,最后告诉 Typescript 类型是正确的。
  • 如果这意味着在 reduce 中添加不兼容的道具会被捕获,我会使用@IAMTHEBEST 建议的方法,但事实并非如此。无论如何,TS 都很满意,这使我更倾向于将对象变成我知道正确的形状,然后按照 Grégory 的建议将其标记为正确的形状。 TS不能做到这一点真是太可惜了。
  • 在“做打字稿”时哈哈大笑。所以没有更好的方法来做到这一点?
猜你喜欢
  • 1970-01-01
  • 2018-09-17
  • 2020-04-28
  • 1970-01-01
  • 2022-08-22
  • 2021-11-25
  • 2021-06-19
  • 2018-04-29
  • 2020-06-29
相关资源
最近更新 更多