给出下面的例子,有什么方法可以实现类似于foobarA的枯燥代码吗?

interface F<T, U extends string> { t: T, f: (u: U) => void }
declare const foo: <T, U extends string>(type: U) => F<T, U>;

// the following correctly types foobar, however 'bar' redundantly repeats.
const foobar = foo<string, 'bar'>('bar')

// ideally one would want the generic inference to be smarter and the
// following to work:
const foobarA = foo<string>('bar')

推荐答案

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

Typescript相关问答推荐

net::BER_RECTION_REUSED和Uncatch使用Axios和TanStack-Query useMutation时未捕获错误(DelivercMutation)

根据另一个成员推断类成员的类型

如何从TypScript中的接口中正确获取特定键类型的所有属性?

angular 17独立使用多个组件(例如两个组件)

在TypeScript中,除了映射类型之外还使用的`in`二进制运算符?

在映射类型中用作索引时,TypeScrip泛型类型参数无法正常工作

已解决:如何使用值类型限制泛型键?

有没有可能产生输出T,它在视觉上省略了T中的一些键?

在另一个类型的函数中,编译器不会推断模板文字类型

是否可以判断某个类型是否已合并为内部类型?

如何以Angular 导入其他组件S配置文件

如何在React组件中指定forwardRef是可选的?

将布尔值附加到每个对象特性

如何将通用接口的键正确设置为接口的键

埃斯林特警告危险使用&as";

导航链接不触发自定义挂钩

Typescript:是否将联合类型传递给重载函数?

Typescript 子类继承的方法允许参数中未定义的键

根据索引将元组拆分为两个块

如何在 ngFor 循环中以Angular 正确动态渲染组件