我有一个“选项”元组[string,function]
,该元组提供一个string
来标识一个检查,以及一个function
,将在其上执行该检查。
(无法通过功能分析找出执行检查的方法,因此必须通过该字符串指示实际检查。)
在我为实现此目的而编写的代码中,在我看来,检查的类型和转换函数的类型不会错配。
但是TypeScript不赞成,给了我一个不兼容的错误。
// tsconfig.json
// {"compilerOptions": {"noImplicitAny": true}};
// Types and interfaces
interface f1_sig { (x:string): string }
interface f2_sig { (x:number): number }
interface f1Chk_sig { (f1:f1_sig): boolean }
interface f2Chk_sig { (f2:f2_sig): boolean }
type options_type =
['f1',f1_sig] |
['f2',f2_sig] ;
interface optionsDictionary_indexer {
f1: f1Chk_sig;
f2: f2Chk_sig;
}
// Implementations
const f1: f1_sig = x => x;
const f2: f2_sig = x => x;
const f1Chk: f1Chk_sig = f => f('0')?true:false;
const f2Chk: f2Chk_sig = f => f( 0 )?true:false;
const optionsDictionary: optionsDictionary_indexer = {
f1: f1Chk,
f2: f2Chk
};
// Alternative 1
const optionsExtractor_1:
(options: options_type) => boolean
=
options =>
optionsDictionary[options[0]](options[1])
// Error in the text editor: 'f1Chk | f2Chk' has no compatible call signatures
// Alternative 2
const optionsExtractor_2:
(options: options_type) => boolean
=
options =>
options[0]==='f1' ? f1Chk(options[1]) :
options[0]==='f2' ? f2Chk(options[1]) : false;
// Error in the text editor: Argument of type 'f1Chk | f2Chk' is not assignable to parameter of type f2_sig
如何混合类型?我哪里错了?如果我没记错的话,有人能提出一种轻松的方法来减轻TypeScript的恐惧吗,因为担心f1Chk
被f2
调用或f2Chk
被f1
调用?
答案 0 :(得分:3)
这里有两件事。
您的“替代1”遇到了一个问题,我称之为“相关类型”,其中您有一个表达式在联合类型上无效,即使该表达式对每个联合类型均有效该联盟的可能范围缩小。在TypeScript中,目前还没有很好的解决方案。我已经suggested允许您强迫编译器解决可能的缩小问题,但实现的可能性很小。也许总有一天,控制流分析将足够复杂,可以正常工作。但就目前而言,我所知道的唯一解决方法是类型断言或冗余代码。
您的“替代2”是我正在谈论的冗余代码。但这仍然行不通!这是由于outstanding bug导致,当您对access the property使用括号表示法时,对属性的控制流分析不起作用。如果您使用点表示法访问元组属性,则代码不会出错...但是不幸的是,没有办法对数字索引使用点表示法。您可以将代码更改为使用某些内容而不是元组,例如:
type options_type =
{zero: 'f1', one: f1_sig} |
{zero: 'f2', one: f2_sig};
// Alternative 2, works now
const optionsExtractor_2:
(options: options_type) => boolean
=
options =>
options.zero === 'f1' ? f1Chk(options.one) :
options.zero === 'f2' ? f2Chk(options.one) : false;
但是您可能应该只使用类型断言,这是比编译器更聪明时的推荐方法:
interface fEitherChk_sig { (f12: f1_sig | f2_sig): boolean }
// Alternative 1
const optionsExtractor_1:
(options: options_type) => boolean
=
options =>
(optionsDictionary[options[0]] as fEitherChk_sig)(options[1])
希望有帮助。祝你好运!