typescript - 打字稿:参数顺序会影响类型推断吗?
问题描述
我有以下类型:
type State<C, S> = {
onEnter?: (context: C) => void;
onExit?: (context: C) => void;
transitions?: (context: C) => S | undefined;
};
class FSM<C, S extends Record<keyof S, State<C, keyof S>>> {
constructor(public readonly states: S, public readonly context: C) {
/* ... */
}
}
如果我像这样实例化它们:
const context = { foo: "bar" };
const f = new FSM(
{
a: { transitions: c => "b" }, // ERROR: c is implicitly any
b: { transitions: c => "a" } // ERROR: c is implicitly any
},
context
);
c
编译器隐含地抱怨any
它无法解析S
(它出现为never
)的类型。显式键入c
可以解决问题,例如:
a: { transitions: (c:typeof context) => "b" },
b: { transitions: (c:typeof context) => "a" }
这是为什么?它不应该能够从构造函数的参数中推断C
出来吗?context
FSM
Wild Ass Guess:构造函数中参数的顺序是否FSM
重要?是不是它试图先解决类型,states
但还不知道类型context
?如果是这样,有没有办法帮助编译器“向前看”?
注意:我很难理解的另一件事是,如果我显式c
使用随机类型键入 - 例如transitions: (c:number)=>"a";
编译器抱怨c
与上下文类型不匹配。所以编译器知道什么是类型c
,但它需要我证明我也知道吗?
解决方案
如果有多个候选者,参数顺序可能对推理很重要,但情况并非如此。您在这里真正想要的是使用上下文类型,这是编译器根据要分配函数的类型推断参数类型的地方(在这种情况下)。
我不确定上下文类型何时放弃的机制,但如果分配给类型需要其他类型参数,它很有可能会停止工作。一个简单的解决方法是通过在与类型参数的交集中指定参数类型中的更简单类型来帮助上下文输入。这将确保我们仍然捕获S
传入的实际类型,但我们为上下文类型提供了一个更简单的路径来推断参数类型:
type State<C, S> = {
onEnter?: (context: C) => void;
onExit?: (context: C) => void;
transitions?: (context: C) => S | undefined;
};
class FSM<C, S extends Record<keyof S, State<C, keyof S>>> {
// Record<string, State<C, keyof S>> added for contextual typing
constructor(public readonly states: S & Record<string, State<C, keyof S>>, public readonly context: C) {
/* ... */
}
}
const context = { foo: "bar" };
const f = new FSM(
{
a: { transitions: (c) => c.foo != "" ? "a" : "b" },
b: { transitions: (c) => "a" },
c: { transitions: (c) => "d" }, // Error, d is not in the state keys
},
context
);
推荐阅读
- python - MacO 上的证书验证失败
- angular - 在 nativescript angular 中,component.ts 和 html 上的变量的双重绑定在某些页面中不起作用。(虽然仅在登录页面中工作)
- angular - Angular 7 Reactive Form Builder,自定义交叉验证器不起作用
- python - Keras网络训练速度下降
- cordova - ionic 3 Location Accuracy Get Error Object(...) 不是函数
- javascript - 使用正则表达式重命名对象数组的键
- java - 字节码中的内部 kotlin 修饰符是什么?
- c++ - 如何正确使用矩阵进行数学运算以进行 opengl 转换?
- android - RecyclerView 在项目插入时显示错误的元素
- javascript - 错误:无法读取未定义的属性“get”。如何使用 bot.channnels.get 函数?