以下代码无法在TypeScript 2.1.4中编译,并给出错误:
错误
错误:(6,31)TS2349:无法调用类型缺少调用签名的表达式。输入'((args:string [],action:A)=> string [])| ((args:string [],action:C)=> string [])'没有兼容的呼叫签名。
代码
/*
* Set up a function to take some arguments
* and an action and use the map to run the appropriate
* function bases on the type property of the action
*/
const caller = (args: string[] = [], action): string[] => {
return map[action.type] ? map[action.type](args, action) : args;
};
interface Action {
type: any;
}
const TYPE_A = "type_a";
interface A extends Action {
from: number;
to: number;
id?: number; // optional parameters causing the issue.
prop1?: number;
}
const TYPE_B = "type_b";
interface B extends Action {
from: number;
to: number;
}
const TYPE_C = "type_c";
interface C extends Action {
id: number;
prop1: number;
}
const map = {
[TYPE_A]: (args: string[], action: A) => {
return ["a"];
},
[TYPE_B]: (args: string[], action: B) => {
return ["b"];
},
[TYPE_C]: (args: string[], action: C) => {
return ["c"];
}
};
caller([], {type: TYPE_A, from: 2, to: 1});
动机
我将表达式用作地图中的属性的动机是,我可以更改属性常量的值,而无需重构地图。
解决方案
有两种方法可以解决这个问题:
a)删除interface A
中的可选字段。
interface A extends Action {
from: number;
to: number;
id: number; // optional parameters causing the issue not optional.
prop1: number;
}
b)将地图属性声明更改为值而不是表达式并保留可选字段。
const map = {
"type_a" : (args: string[], action: A) => {
return ["a"];
},
"type_b": (args: string[], action: B) => {
return ["b"];
},
"type_c": (args: string[], action: C) => {
return ["c"];
}
};
问题
我的问题是为什么首先显示错误,有人可以向我解释这个吗?
答案 0 :(得分:0)
原因是A
和C
不兼容,因为prop1
中的A
是可选的,C
中是必需的。因此,您不能使用需要C
的函数,其中需要A
的函数:
let fa: (a: A) => void;
let fc: (c: C) => void;
fa = fc;
fc = fa;
错误:
test.ts(49,1): error TS2322: Type '(c: C) => void' is not assignable to type '(a: A) => void'.
Types of parameters 'c' and 'a' are incompatible.
Type 'A' is not assignable to type 'C'.
Property 'id' is optional in type 'A' but required in type 'C'.
test.ts(50,1): error TS2322: Type '(a: A) => void' is not assignable to type '(c: C) => void'.
Types of parameters 'a' and 'c' are incompatible.
Type 'C' is not assignable to type 'A'.
Property 'from' is missing in type 'C'.
当您声明具有文字属性名称的地图时,类型推断可以确定何时执行caller([], {type: TYPE_A, from: 2, to: 1});
,您实际上是使用"type_a"
键访问值,因此它知道函数参数类型正是A
。当使用计算键声明map时,它不能这样做,可能是因为它只是在编译时不计算键的表达式,因此它推断出映射值的联合类型,并且union的两个成员彼此不兼容,因为A
和C
不兼容。
您也可以通过明确声明map
的类型来解决这个问题:
const map: {[key: string]: (args:string[], action: Action) => string[]} = {
[TYPE_A]: (args: string[], action: A) => {
return ["a"];
},
[TYPE_B]: (args: string[], action: B) => {
return ["b"];
},
[TYPE_C]: (args: string[], action: C) => {
return ["c"];
}
};
也有效。