好问题。。。对于这个相当长的答案,有两种可行的选择。你问了两个问题,我分别回答。
问题1:
有没有办法使减速器类型更严格地要求这两个参数。。。
障碍1:丢弃功能参数
is documented here
在“比较两个函数”标题下它说“我们允许‘丢弃’参数。”也就是说,参数较少的函数可分配给参数较多的函数。这个
rationale is in the FAQ
. 简而言之,以下赋值是安全的,因为参数较少的函数“可以安全地忽略额外的参数”
const add: (x: number, y: number) =
(x: number) => { return x; }; // works and is safe
障碍2:函数参数双变量
第二个障碍是
function parameters are bivariant
. 那个
不能
Pair
以及接受
class Pair {
x: number;
y: number;
}
let addPair: (p: Pair) => number;
一对
.
substitutability rules
,但函数遵循双变量规则。在其简单的类型分配中,TypeScript允许我们分配类型
到类型
Single
但不指定类型
到类型
一对
. 这是预期的替代品。
class Single {
x: number;
}
let s: Single = new Pair(); // works
let p: Pair = new Single(); // fails because of a missing property.
let addSingle: (s: Single) => number;
addSingle = (p: Pair) => p.x + p.y; // as expected, Pair is assignable to Single.
let addPair: (p: Pair) => number;
addPair = (s: Single) => s.x; // surprise, Single is assignable to Pair!
结果是,一个函数期望
将接受
仅有一个的
影响
Reducers
以下两种技术都不会强制执行以下参数(或类属性)的数量:
Reducer
实施必须接受。
class Action { }
// no restriction - TypeScript allows discarding function parameters
type Reducer01<S> = (state: S, action: Action) => S;
const reducer01: Reducer01<number> = (state: number) => 0; // works
// no restriction - TypeScript functions have parameter bivariance
class ReducerArgs<S> {
state: S;
action: Action;
}
type Reducer02<S> = (args: ReducerArgs<S>) => S;
const reducer02 = (args: { state: number }) => 0; // works
实际上,这可能不会成为问题,因为让
ReducersMapObject
接受a
减速器
参数更少是安全的。编译器仍将确保:
-
包括
这个
减速器
参数,以及
-
每个实现一个
仅对其(可能较短)参数列表进行操作。
...或者用另一种方法来更确信ReducerMapObject实际上包含reducer函数?
reducerCreator
函数(和其他形状异常的函数)与
Reducer<S>
可行选项1:用户定义的参数类型
ReducerArgs<S>
,将给我们
更多
还原干燥器
interface Action {
type: any;
}
// define an interface as the parameter for a Reducer<S> function
interface ReducerArgs<S> {
state: S;
action: Action
}
type Reducer<S> = (args: ReducerArgs<S>) => S;
const reducer: Reducer<string> = (args: ReducerArgs<string>) => args.state;
const reducerCreator = (n: number): Reducer<string> => reducer;
interface ReducersMapObject {
[key: string]: Reducer<any>;
}
const reducerMap: ReducersMapObject = {
test: reducer,
test2: reducerCreator // error!
}
可行选项2:泛型和联合类型
另一种选择是使用泛型
ReducerMapObject<T>
这样地:
interface ReducersMapObject<T> {
[key: string]: Reducer<T>;
}
然后用
a union type
const reducer: Reducer<string> = (state: string, action: Action) => state;
const reducer1: Reducer<number> = (state: number, action: Action) => state;
const reducerMap: ReducersMapObject<string | number> = {
test: reducer,
test1: reducer1,
test2: reducerCreator // error!
}
结果就是
any => any
变成
T => T
T
是联合中列出的类型之一。(顺便说一句,最好有一个类型,上面写着“x可以是任何类型,只要它是与y相同的类型”)
虽然以上两个都涉及更多的代码,并且有点笨拙,但它们确实符合您的目的。这是一个有趣的研究项目。谢谢你的提问!