![](/img/trans.png)
[英]Returned type of a function is not inferred when it's declared as generic from the function's argument
[英]Generic type params not inferred when argument is a function
在这段代码中,我在这里:
type GETR<a extends string, b extends string> = [a,b]
interface Options<A extends string, B extends string> {
bar: GETR<A,B>
}
function foo<A extends string, B extends string, C extends Options<A, B>>(r: C) {
return r
}
const bar:GETR<"foo", "bar"> = null as any as GETR<"foo", "bar">
const x = foo({ bar })
没有类型错误。 看这里
现在,如果我只更改从[a,b]
到(k:a) => b
的 GETR 类型,而没有其他更改。 然后不再推断泛型类型参数,我有一个类型错误:
type GETR<a extends string, b extends string> = (k:a) => b
interface Options<A extends string, B extends string> {
bar: GETR<A,B>
}
function foo<A extends string, B extends string, C extends Options<A, B>>(r: C) {
return r
}
const bar:GETR<"foo", "bar"> = null as any as GETR<"foo", "bar">
const x = foo({ bar })
有类型错误。 看这里
我试图理解为什么,最好的解决方法是什么?
我相信这是因为逆变。 但是,我不是 100% 确定,因为它也可能是不变的。 有一个简单的解决方法,只需去掉C
通用参数:
type Fn<Arg extends string, Return extends string> = (k: Arg) => Return
interface Options<Arg extends string, Return extends string> {
prop: Fn<Arg, Return>
}
function foo<
Arg extends string,
Return extends string,
>(r: Options<Arg, Return>) {
return r
}
declare const prop: Fn<"foo", "bar">
const x = foo({ prop }) // ok
考虑这个小例子:
declare let stringString: Options<string, string>
declare let fooBar: Options<'foo', 'bar'>
stringString = fooBar // error
fooBar = stringString // error
您可能已经注意到: stringString
和fooBar
不能相互分配。
问题出在Arg
泛型类型中(在您的示例中是a
)。 如果您摆脱Arg
( a
),您的示例将编译:
type Fn<Return extends string> = () => Return
type Options<Return extends string> = {
prop: Fn<Return>
}
function foo<
Return extends string,
C extends Options<Return>
>(r: C) {
return r
}
declare const prop: Fn<"bar">
const x = foo({ prop }) // no error
它可以编译,因为Return
在协变 position 中。
让我们尝试加回Arg
但去掉Return
:
type Fn<Arg extends string> = (arg: Arg) => void
type Options<Arg extends string> = {
prop: Fn<Arg>
}
function foo<
Arg extends string,
C extends Options<Arg>
>(r: C) {
return r
}
declare const prop: Fn<"foo">
const x = foo({ prop }) // still error
declare let stringPrimitive: string;
declare let fooBarPrimitive: 'bar'
stringPrimitive = fooBarPrimitive // ok
fooBarPrimitive = stringPrimitive // error
declare let stringString: Options<string>
declare let fooBar: Options<'bar'>
stringString = fooBar // error
fooBar = stringString // ok
仍然有错误。 请检查stringPrimitive
、 fooBarPrimitive
、 stringString
和fooBar
的可分配性。
在第一个示例中, fooBarPrimitive
文字类型可分配给字符串,这是预期的。 但是,在第二个示例中, fooBar
由于contravariance
不能再分配给stringString
。 Function arguments 处于逆变位置。
让我们尝试添加Return
generic(在您的示例中为b
):
type Fn<Arg extends string, Return extends string> = (arg: Arg) => Return
type Options<Arg extends string, Return extends string> = {
prop: Fn<Arg, Return>
}
function foo<
Arg extends string,
Return extends string,
C extends Options<Arg, Return>
>(r: C) {
return r
}
declare const prop: Fn<"foo", 'bar'>
const x = foo({ prop }) // still error
declare let stringString: Options<string, string>
declare let fooBar: Options<'foo', 'bar'>
stringString = fooBar // error
fooBar = stringString // error
请检查stringString
和fooBar
的可分配性,它们根本无法相互分配。 在这两种情况下,您都会遇到错误。
据我了解,添加C
泛型会触发Arg
泛型的contravariant
行为。
这不是我第一次面对这样的行为。
考虑这个例子,但请关闭strictFunctionTypes
标志:
type Animal = { tag: 'animal' }
type Dog = Animal & { bark: true }
type Cat = Animal & { meow: true }
declare let animal: (x: Animal) => void;
declare let dog: (x: Dog) => void;
declare let cat: (x: Cat) => void;
animal = dog; // ok without strictFunctionTypes and error with
dog = animal; // should be ok
dog = cat; // should be error
dog
可以分配给animal
,但不应该。
现在,尝试将泛型添加到animal
function:
type Animal = { tag: 'animal' }
type Dog = Animal & { bark: true }
// generic is here
declare let animal: <T extends Animal>(x: T) => void;
declare let dog: (x: Dog) => void;
animal = dog; // error even without strictFunctionTypes
现在,即使没有strictFunctionTypes
标志, dog
也不能分配给animal
。 我没有在文档中找到对这种行为的解释。
请参阅此处的相应文章
如果您对 *-variance 主题感兴趣,请查看此答案。
PS如果有人能证实或批评我的想法,我会很高兴,我已经尽力了
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.