【发布时间】:2021-10-20 02:38:14
【问题描述】:
下面的代码块会产生一个打字错误,因为虽然我们知道foo[k]和bar[k]是同一类型,但TS无法知道(好吧,也许通过某种魔法可以,但是显然没有)
interface IMixed {
a: number;
b: string;
c: boolean;
}
const foo: IMixed = { a: 1, b: 'one', c: true };
const bar: IMixed = { a: 2, b: 'two', c: false };
(Object.keys(foo) as Array<keyof IMixed>).forEach(k => {
foo[k] = bar[k];
// ^^^^^^ Type 'string | number | boolean' is not assignable to type 'never'.
});
当 TS 无法判断出我知道是真的某件事时,我会施放它。但是在这种情况下,虽然我知道这是一个有效的分配,但我不知道它是哪种类型......我只知道它们是相同的。我无法在这里找到一种优雅的方式来使用泛型。
假设我致力于迭代这些属性的做法(比如说,因为我们希望属性确实会添加到最后一行,并且类似的代码存在于整个代码库中......)
简而言之:我如何断言这个赋值是有效的?
(附带问题:为什么错误将受让人称为“从不”类型?)
更新
@captain-yossarian 对可变性提出了一个很好的观点,并提出了一个完全可行的不可变解决方案。不过,我觉得这个问题仍然悬而未决,如果这个例子有点诡计:
interface IMixed {
a: number[];
b: string[];
c: boolean[];
}
const foo: IMixed = { a: [1], b: ['one'], c: [true] };
const bar: IMixed = { a: [2], b: ['two'], c: [false] };
function intersection<T>(...arrays: T[][]): T[] {
return [...new Set([].concat(...arrays))]
}
(Object.keys(foo) as Array<keyof IMixed>)
.reduce((acc, elem) => ({
...acc,
[elem]: intersection(foo[elem], bar[elem])
// ^^^^^^^^^ Argument of type 'string[] | number[] | boolean[]' is not
// assignable to parameter of type 'string[]'.
}), foo);
关键是,赋值显然要求类型兼容......但intersection 函数也是如此。所以这就像原始问题的不可变版本。
【问题讨论】:
-
想必您正在寻找比
// @ts-ignore更细致、更有帮助的东西;-) -
爱 @ts-ignore ;-) ...但 linter 不会让我 :)
-
@geofh 进行了更新。现在可以变异
foo -
在上面的例子中
k是一个联合'a' | 'b' | 'c'。为了缩小值类型 TS 需要 specific 键。您可以提取和使用接受特定keyof IMixedtypescriptlang.org/play?#code/… 的通用函数 -
never表示您定义的类型不存在这种情况。比如尝试访问let a: number = 0;在 if 块中,例如if(typeof a === 'string').
标签: typescript