我希望能够创建一个函数工厂来更新 Redux 存储的子部分。在下面的示例中,编译器提示 state[key]
可能是一个联合。有没有办法在运行时将 K 限制为 "foo"
或 "bar"
?
interface State {
foo: number[];
bar: string[];
}
const createUpdater = <K extends keyof State>(key: K) => (
state: State,
id: number,
updater: (subState: State[K][number]) => State[K][number]
) => {
const elements: State[K] = [...state[key]]; // <--- Error
elements[id] = updater(elements[id]);
return {
...state,
[key]: elements
};
};
const fooUpdater = createUpdater("foo");
const barUpdater = createUpdater("bar");
错误消息:
Type '(string | number)[]' is not assignable to type 'State[K]'.
Type '(string | number)[]' is not assignable to type 'number[] & string[]'.
Type '(string | number)[]' is not assignable to type 'number[]'.
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.ts(2322)
最佳答案
基于TypeScript Playground ,这是 3.5.1 中的问题,但在 3.6.3 和 ES7-beta 中仅在 ES3/ES5 目标中:ES2015 及更高版本似乎没问题。在这两种情况下,K 都被适本地限制为 K extends "foo" | "bar"
。目标级别更改导致类型推断错误这一事实使我认为这是一个错误。
这可能与 TS 3.5's "Smarter Union Type Checking" 有关,但听起来与 TS 3.6's "More Accurate Array Spread" 更相关,特别是考虑到 ES5 中生成的代码使用 __spreadArray
.
作为解决方法,您可以使用类型断言来说服 TypeScript state[key]
可以复制为State[K]
,但如“更准确的数组传播”部分 slice
中所述语义与您的传播略有不同。
const elements = state[key].slice() as State[K];
关于typescript - 如何在运行时将联合限制为一种给定类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58328115/