打字稿重载、可选参数和类型推断
Posted
技术标签:
【中文标题】打字稿重载、可选参数和类型推断【英文标题】:Typescript overloads, optional arguments and type inference 【发布时间】:2019-09-15 01:58:49 【问题描述】:我目前正在研究 Typescript 中的重载。
假设我有一个重载的函数:
function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(foo?: boolean, bar?: boolean)
if (foo === true || foo === false)
const result = bar;
函数要么不带参数调用,要么带两个参数(foo 和 bar)调用。根据 vscode 的智能感知,result
变量的类型为 boolean | undefined
。
即使我已经测试了foo
参数,为什么bar
可以是undefined
?如果foo
exists,类型推断不应该预测bar
exists 也存在吗?
【问题讨论】:
你可以看看这个答案:Is there a way to do method overloading in TypeScript? 【参考方案1】:这里的第一个问题是允许重载函数的实现签名比任何调用签名都宽松。在实现内部,编译器只检查实现签名。这意味着在您的函数内部,foo
和 bar
都独立于 boolean | undefined
类型,并且无法恢复这样一个事实,即调用该方法的任何人都将指定两者或都不指定。
TypeScript 最近添加了对rest/spread tuples in function parameters 的支持,因此您可以像这样重写您的函数签名:
declare function method(...args: [] | [boolean, boolean]);
method(); // okay
method(false); // errror
method(true, false); // okay
现在 TypeScript 知道 args
到 method()
要么是空元组,要么是一对 boolean
值。如果你愿意,你可以保留重载,只是让实现签名更窄:
function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(...args: [] | [boolean, boolean])
const foo = args[0];
const bar = args[1];
if (foo === true || foo === false)
const result = bar; // oops, still boolean | undefined
不幸的是,推理仍然不起作用,这是第二个问题:TypeScript 的控制流分析根本没有我们那么聪明。虽然我们了解foo
的类型与bar
的类型相关,但编译器却没有。如果缩小了foo
,但忘记了bar
与foo
有任何关系。解决此问题的一种方法是不要将 foo
和 bar
拆分为单独的类型,而是在单个 args
变量上使用属性访问类型保护。当args
从[] | [boolean, boolean]
缩小到仅[boolean, boolean]
时,您可以确定第二个元素已定义:
function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(...args: [] | [boolean, boolean])
if ('0' in args)
const result = args[1]; // boolean
这可能是代码更改太多,而 IntelliSense 对您来说不值得。如果是这样,并且您愿意让编译器变得更聪明,您可以使用 type assertion 并继续您的一天:
function method(): void;
function method(foo: boolean, bar: boolean): void;
function method(foo?: boolean, bar?: boolean)
if (foo === true || foo === false)
const result = bar as boolean; // I'm smarter than the compiler ?
【讨论】:
以上是关于打字稿重载、可选参数和类型推断的主要内容,如果未能解决你的问题,请参考以下文章