【发布时间】:2021-03-10 18:52:05
【问题描述】:
我有一个简单的reducer,它使用一个对象来累积值。我想尽可能多地使用 TS 推理。 但是我无法让打字稿提供适当的类型安全。它会错误地抱怨,因为空对象不包含任何预期的类型,或者如果我键入对象它根本不会抱怨(而某些键可能会导致未定义的值)。
所以给出这段代码:
type Session = { name: string; startDate: Date; endDate: Date };
type SessionGroup = {
name: string;
duration: number;
sessions: Session[];
};
type Grouped = { [k: string]: SessionGroup };
function selectGroupedSessions(sessions: Session[]): SessionGroup[] {
const grouped = sessions.reduce((result: Grouped, session) => {
const { name, startDate, endDate } = session;
const group = result[name] || { name, sessions: [] };
group.sessions.push(session);
result[name] = group;
return result;
}, {});
return Object.values(grouped);
}
如您所见,我将累加器键入为Grouped。如果我这样做,它不会在这一行给我一个错误:result[name] = group 但它应该是因为我分配的默认值与SessionGroup 的预期类型不兼容。问题显然出在Grouped 类型上,它表示,对于每个可能的字符串键,都有一个 SessionGroup,这显然不是真的。
如果我像这样键入 Grouped 类型:
type Grouped = { [k: string]: SessionGroup | undefined };
然后我在最后一行得到以下类型错误(返回 Object.values)
Type '(SessionGroup | undefined)[]' is not assignable to type 'SessionGroup[]'
那么,为了让 typescript 理解它显然是正确的 JS 代码,最好的输入方法是什么?无需添加大量可笑的铸件
【问题讨论】:
-
如果您打开checked indexed access,它会打开this。我并不是建议您一定要打开它,但如果您这样做,它会捕获上面代码中的错误。这对你有用吗?如果是这样,我会考虑写一个答案来解释索引签名的这种行为。如果没有,请详细说明发生了什么;你说“它错误地抱怨”,但不包括显示它的minimal reproducible example,所以我有点困惑。
-
对“错误投诉”的解释在同一行。理想情况下,我不想输入累加器,打字稿应该能够从外部函数签名中推断出来。在我提供的示例中,您所要做的就是删除结果的类型注释,您将看到我所指的错误。激活检查的索引访问似乎产生了预期的效果,但是我不确定它会如何影响代码库的其余部分。我看到的唯一缺点是数组索引,我从不使用,所以应该没问题。
-
这里有最小可重现的例子:typescriptlang.org/play?#code/…
-
啊,我明白了。 Contextual typing 不能通过控制流任意向后工作;如果是这样,你在 TypeScript 中几乎不会出错,即使是有明显问题的代码也是如此。如果你写
let i = 0; i = "hello",你会得到一个合理的错误,"hello"不是number。但是有人可能会争辩说,编译器应该使用上下文类型来推断i应该是string | number,因为您稍后会使用它来存储string。有机会我可以写一个答案。
标签: typescript