简体   繁体   English

打字稿:参数顺序会影响类型推断吗?

[英]Typescript: Does parameter order affect type inference?

I have the following types:我有以下类型:

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) {
        /* ... */
    }
}

If I instantiate them like this:如果我像这样实例化它们:

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
);

The compiler complains that c is implicitly any and it's unable to resolve the type of S (it comes up as never ).编译器抱怨c是隐式any并且它无法解析S的类型(它出现为never )。 Explicitly typing c fixes the issue, eg:显式输入c解决问题,例如:

a: { transitions: (c:typeof context) => "b" },
b: { transitions: (c:typeof context) => "a" } 

Why is that?这是为什么? Shouldn't it be able to infer C from the context parameter of the FSM constructor?它不应该能够从FSM构造函数的context参数中推断出C吗?

Wild Ass Guess : Does the order of the parameters in the FSM constructor matter? Wild Ass GuessFSM构造函数中参数的顺序重要吗? Is it that it tries to resolve the type of states first and does not yet know about the type of context ?是不是它首先尝试解析states类型并且还不知道context的类型? If so is there a way to help the compiler "look ahead"?如果是这样,有没有办法帮助编译器“向前看”?

NOTE : Another thing that I have a hard time understanding about this is that if I explicitly type c with a random type - eg transitions: (c:number)=>"a";注意:我对此很难理解的另一件事是,如果我使用随机类型显式键入c - 例如transitions: (c:number)=>"a"; the compiler complains that c doesn't match the type of context.编译器抱怨c与上下文类型不匹配。 So the compiler knows what type c is but it needs me to show it that I know it too?所以编译器知道c是什么类型,但它需要我证明我也知道它?

Parameter order can matter to inference if there are multiple candidates, but this is not that case.如果有多个候选,参数顺序可能对推理很重要,但事实并非如此。 What you really want here is to use contextual typing, this is where the compiler infers the type of parameters (in this case) based on the type of where the function is to be assigned.您在这里真正想要的是使用上下文类型,这是编译器根据要分配函数的位置的类型推断参数类型的地方(在这种情况下)。

I am not sure of the mechanics of when contextual typing gives up, but if the assigned to type requires other type parameters there is a good chance it will stop working.我不确定上下文类型何时放弃的机制,但如果分配给类型需要其他类型参数,它很有可能会停止工作。 A simple work around is to help contextual typing out by specifying an simpler type in the type of the parameter in an intersection with the type parameter.一个简单的解决方法是通过在与类型参数相交的参数类型中指定更简单的类型来帮助上下文输入。 This will ensure we still capture in S the actual type passed in but we give contextual typing a simpler path to infer the parameter types:这将确保我们仍然在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
);

Playground Link 游乐场链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM