当将字符串与另一个类型化函数一起传递给泛型函数时,字符串缩小为String Literal类型



在下面的示例中,我有一个函数,它将泛型类型V作为参数,还有另一个函数也将V作为参数。

当我用一个字符串和一个匿名函数调用该函数时,该函数从原始函数的签名中推断出其参数的类型,我会得到一个按预期键入的结果:string

然而,当我用符合签名的单独声明的函数调用它时,字符串参数的类型会缩小为字符串文字。

type Placeholder<V> = (value: V) => void;
const myTestFunction = <V extends any>(
value: V,
placeholder: Placeholder<V>
) => {
return value;
}
const aTypedFunction = (value: string) => { return };
// "isLiteralType"
const typedResult       = myTestFunction("isLiteralType", aTypedFunction);
// "string"
const inferredResult    = myTestFunction("isStringType", (value) => { return });

TS游乐场

这似乎是由于在aTypedFunction中显式键入了value参数,因为在匿名函数中显式输入参数也会产生字符串文字结果。然而,我不知道为什么会出现这种情况!

为什么会发生这种类型缩小,我如何更改myTestFunctionaTypedFunction,使前者接受后者作为参数而不缩小类型

类型参数通常是从一个参数中推断出来的;对于函数,V将从参数value: V中推断出来,因为它的类型是原始类型参数,所以在调用函数时,可以很容易地推断出类型V——只需查看调用中第一个参数的类型,并将其用于V。这就是这里发生的事情,这就是为什么V在调用myTestFunction("isLiteralType", aTypedFunction)中被推断为"isLiteralType"

当您直接传递类型化的箭头函数时,同样适用。也就是说,我真的不知道为什么使用未键入的箭头函数会得到不同的结果。我和你一样对此感到好奇。

幸运的是,我们不需要弄清楚为什么第二个例子表现不同:有了类型参数通常会从更容易推断的参数中推断出来的知识,如果我们想从placeholder而不是value推断类型参数,就把它设为placeholder: P而不是value: V。我在下面写了一个解决方案,它从P派生value的类型,而不是从V派生placeholder的类型。

type Placeholder<V> = (value: V) => void;
type PlaceholderComponent<P extends Placeholder<any>> = P extends Placeholder<infer V> ? V : never
const myTestFunction = <P extends Placeholder<any>>(
value: PlaceholderComponent<P>,
placeholder: P
) => {
return value;
}
const aTypedFunction = (value: string) => { return };
// string
const typedResult       = myTestFunction("isLiteralType", aTypedFunction);

还要注意,使用非类型化回调的调用将导致any而不是string;这是有道理的,因为没有类型注释的参数在无法从上下文推断其类型时,默认情况下具有类型any

游乐场链接

相关内容

最新更新