在microsoft/TypeScript#26242中,TypeScrip不直接支持partial type argument inference.所以,如果你有一个表格的generic函数:
declare const foo: <T, U extends string>(u: U) => F<T, U>;
没有办法调用它,以便手动指定T
,但让编译器推断U
:
// const foobarA: F<string, unknown> ☹
const foobar = foo<string, "bar">("bar");
要么像在foo<string, "bar">("bar");
中那样手动指定两个类型参数(不幸的是,这是多余的),要么像在foo("bar")
中那样让编译器推断这两个参数(它不能推断出T
的正确类型).
除非这一点改变,否则您将需要解决它.
一种解决办法currying,将单个泛型函数调用拆分成多个泛型函数调用,以便您可以手动指定第一个泛型函数调用的类型参数,然后让编译器推断第二个泛型函数调用的类型参数.这意味着我们需要将上面的foo()
重构为
declare const foo: <T, >() => <U extends string>(u: U) => F<T, U>;
然后我们可以像这样调用该函数:
declare const foo: <T, >() => <U extends string>(u: U) => F<T, U>;
const foobarA = foo<string>()("bar");
// const foobarA: F<string, "bar">
不得不抛出额外的函数调用有点恼人,但至少从语法上讲,它只是另一对括号,它正好给出了您正在寻找的行为.
另一种解决方法是添加对应于您想要手动指定的类型参数的dummy parameter,然后传入该类型的值,以便编译器可以成功地推断它.这看起来是这样的:
declare const foo: <T, U extends string>(dummyT: T, u: U) => F<T, U>
然后我们可以像这样调用该函数:
const foobarA = foo("someString", "bar");
// const foobarA: F<string, "bar">
传递给dummyT
的值"someString"
几乎肯定会被函数实现忽略,但它允许编译器推断T
的值是string
.如果调用方没有Handy类型的值,他们仍然可以使用asserting的伪版本,即某个随机对象属于该类型:
const foobarB = foo(null! as string, "bar");
// const foobarB: F<string, "bar">
在这里,我使用了null!
,值是null
,到了asserting that it is non-null
via postfix !
,我们得到了一个不可能的"非空值"the never
type,它可以分配给任何其他类型.像null!
这样令人费解的东西的主要好处是,只需击键五次就能产生不可能的never
类型的值,编译器可以断言as string
而不会有任何抱怨.
这两种版本都可以工作;我倾向于使用Currate,除非用例使调用者可以很容易地找到并为伪参数传递适当的实参.
Playground link to code个