打字稿类型推断未按预期工作

问题描述 投票:0回答:1

我有两个非常相似的函数,但打字稿只能推断其中一个的返回值:

interface URItoKind<A> {}
type URIS = keyof URItoKind<any>;
type Kind<URI extends URIS, A> = URItoKind<A>[URI];

const URI = "Option";
export type URI = typeof URI;
interface URItoKind<A> {
  readonly [URI]: Option<A>;
}
class Option<A> {
  static of: <A>(a: A) => Option<A>;
}

function test1<F extends URIS, A, B>(f: (a: A) => Kind<F, B>): Option<B>;

function test2<F extends URIS>(): <A, B>(f: (a: A) => Kind<F, B>) => Option<B>;

const func = (x: number) => Option.of(x.toString()); // (x: number) => Option<string>
const r1 = test1(func); // Option<unknown> - Doesn't work
const r2 = test2()(func); // Option<string> - Works Fine
javascript typescript types functional-programming
1个回答
0
投票

这是由于 TypeScript 有时为了性能而“懒惰”的方式造成的。

测试1

function test1<F extends URIS, A, B>(f: (a: A) => Kind<F, B>): Option<B>;

一旦您调用

test1(func)
,TypeScript 就会尝试推断类型。问题是 TS 采用
F extends URIS
并用它来推断
Kind<F, B>
。 TypeScript 在某些情况下会针对性能进行优化,在这种情况下,TypeScript 会变得“懒惰”,以便更快地推断类型。

测试2

function test2<F extends URIS>(): <A, B>(f: (a: A) => Kind<F, B>) => Option<B>;

在这种情况下,你必须打电话。第一次调用会触发 TypeScript 尝试推断 F,但没有足够的信息,因此 TypeScript 会等到第二次调用。在第二次调用中,没有像

F extends URIS
这样的“提示”,因此 TypeScript 推断出
F
,但这一次它不会以懒惰的方式执行此操作。它会遍历所有通用类型,直到找到真正的答案。

解决方案

您可以消除通用约束

F extends URIS
以防止打字稿“懒惰”,而不提示意味着TS需要一直向下推断类型。

declare function test1<A, B>(f: (a: A) => Kind<URIS, B>): Option<B>;
declare function test2(): <A, B>(f: (a: A) => Kind<URIS, B>) => Option<B>;

现在两者都按预期工作:

const func = (x: number) => Option.of(x.toString()); // (x: number) => Option<string>
const r1 = test1(func); // Option<string> - Works Fine
const r2 = test2()(func); // Option<string> - Works Fine
© www.soinside.com 2019 - 2024. All rights reserved.