繁体   English   中英

当参数是 function 时不推断通用类型参数

[英]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

您可能已经注意到: stringStringfooBar不能相互分配。

问题出在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


操场

仍然有错误。 请检查stringPrimitivefooBarPrimitivestringStringfooBar的可分配性。

在第一个示例中, 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

操场

请检查stringStringfooBar的可分配性,它们根本无法相互分配。 在这两种情况下,您都会遇到错误。

据我了解,添加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.

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