TypeScript 参数类型缩小应该考虑函数重载签名,

jei2mxaa  于 6个月前  发布在  TypeScript
关注(0)|答案(4)|浏览(63)

TypeScript版本: 2.2.1
代码

interface A { x: number; }
interface B { y: number; }

function foo(b: B): void;
function foo(a: A, b: B): void;
function foo(a: A|B, b?: B): void {
  if(b !== void 0) {
    console.log(a.y); // Error: Property 'y' does not exist on type 'A | B'
  }
}

第三个(统一)函数签名被调用站点隐藏,因此任何参数都应该能够根据提供的参数进行缩小。在上面的例子中,只有在第一个参数的类型为 A 时,第二个参数才会被定义,因此我希望相应地缩小参数类型。有人可能会认为在编译输出中,JavaScript仍然可以传递后续参数,但既然JavaScript总是可以违反TypeScript从中推断出的每个类型约束,那么为什么要缩小类型呢?

xfb7svmp

xfb7svmp1#

这对于两个重载来说是很容易理解的,但对于更复杂的场景就很快变得混乱。要生成一个简洁地定义这些参数之间关系的单一数据结构是非常复杂的:

function fn(x: string, y: number): void;
function fn(x: string, y: string: void;
function fn(x: number, y: number, z: string): void;
function fn(x: number | string, y: number | string, z?: string) {
 // Quick, what checks produce what type guards?
}

我们还没有任何机制来进行“如果x是T,那么y是U”的推断。

tyg4sfes

tyg4sfes2#

你不能使用一个简单的图来表示这个吗?对于每个参数,它应该有一个入口节点,当重载之间出现共同点时,收敛。你可以使用像后缀树这样的东西,它可以回溯到自身。基数树似乎也相关,但受到顺序的限制。然而,这可能是一个多功能解决方案的好灵感。

n3ipq98p

n3ipq98p3#

这是两年后的事情了,但是:

33704 (评论)

在某些情况下,你可以得到你想要的缩小。

bxpogfeg

bxpogfeg4#

有趣的是,一个与#33704具有一定同构性的例子已经按预期工作,因此可能可以解决这个问题:

type __foo_params =
    | {a?: never, b?: never}
    | {a: string, b: string}

function foo(__params: __foo_params): void {
    if (!__params.a) return
    console.log(__params.a.length + __params.b.length) // no error
}

相关问题