gpt4 book ai didi

typescript - 当参数是函数时不推断通用类型参数

转载 作者:行者123 更新时间:2023-12-05 03:18:21 27 4
gpt4 key购买 nike

在我这里的这段代码中:

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

没有类型错误。 See it here

现在,如果我只更改 GETR 的类型,从 [a,b](k:a) => b 没有其他更改。然后不再推断通用类型参数,我有一个类型错误:

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

有类型错误。 See it here

我想了解为什么,最好的解决办法是什么?

最佳答案

我相信这是因为逆变。但是,我不是 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

Playground

考虑这个小例子:

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 处于协变位置。

让我们尝试添加 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


Playground

还是有错误。请检查 stringPrimitivefooBarPrimitivestringStringfooBar 的可分配性。

在第一个示例中,fooBarPrimitive 文字类型可分配给字符串,这是预期的。但是,在第二个示例中,由于逆变fooBar 不再可分配给stringString。函数参数处于逆变位置。

让我们尝试添加 Return 泛型(在您的示例中是 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

Playground

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

据我了解,添加 C 泛型会触发 Arg 泛型的逆变行为。

这不是我第一次遇到这种行为。

考虑这个例子,但请关闭 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 函数:

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。我没有在文档中找到对此行为的解释。

见相应文章here

请查看this answer如果您对 *-方差主题感兴趣。

附言如果有人证实或批评我的想法,我会很高兴,我已经尽力了

关于typescript - 当参数是函数时不推断通用类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73733474/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com