我们有以下代码段:
interface A {
isEmpty(x: any[] | string | object): boolean;
isEmptyObject(x: object): boolean;
}
const a: A = <A>{};
a.isEmptyObject({});
a.isEmptyObject({a: 1});
a.isEmpty([]);
a.isEmpty('');
a.isEmpty({});
a.isEmpty({a: 1});
当我尝试编译它时,它崩溃了:
a.ts(14,12): error TS2345: Argument of type '{ a: number; }' is not assignable to parameter of type 'string | object | any[]'.
Object literal may only specify known properties, and 'a' does not exist in type 'string | object | any[]'.
当联合类型(string | object | any[]
)包含其工作的object
类型时(isEmptyObject
与{a: 1}
的呼叫是否合适),这怎么可能?
主要问题:这是一个TypeScript错误,或者应该如何编写输入可能是任何值或字符串或对象的数组(但不是任何原语,我不想要any
或{ {1}})?
使用TypeScript 2.3.4进行测试。
答案 0 :(得分:4)
这不是一个错误,而是一个支持API-s的功能,它利用了参数对象。以jQuery-s ajax函数为例。它需要一个对象作为参数。
interface JQueryAjaxParam {
url: string;
data?: any;
}
...
$.ajax({
url: "",
datta: "" // notice the typo here
});
在这种情况下确实需要编译错误,即使{url:"",datta:""}
实现了param接口。为了解决这个问题,他们添加了excess property checks for object literals as direct parameters。 这是一件好事,在类型检查器中提供更多信心,并且只有在人们尝试进行像您这样的快速测试时才会导致错误。你必须牢记这一规则,这是额外安全的代价。
更新: TypeScript 2.4另外引入了Weak types
然后有这个签名的函数:
function isEmptyObject(x : object) : void;
这里,意图很清楚,这个功能旨在接受任何带有任何键的对象。仅接受空对象的函数几乎没有用处。因此,他们添加了一个例外:当参数的类型为object
时,则省略前一个检查。
那该怎么办?没有。在实际使用中,你的功能会很好地检测。你可以尝试一下:
interface A {
isEmpty(x: any[] | string | object): boolean;
isEmptyObject(x: object): boolean;
}
const a: A = <A>{};
const param = {a: 1};
a.isEmptyObject({});
a.isEmptyObject(param);
a.isEmpty([]);
a.isEmpty('');
a.isEmpty({});
a.isEmpty(param);
<强>更新强>
您的示例是一个实际的用例,您希望它甚至可以使用文字。在Nitzan之后,我也建议使用函数重载。
interface A {
isEmpty(x: any[]): boolean;
isEmpty(x: string): boolean;
isEmpty(x: object): boolean;
isEmptyObject(x: object): boolean;
}
const a: A = <A>{};
a.isEmptyObject({b: 6});
a.isEmptyObject({a: 1});
a.isEmpty([]);
a.isEmpty('');
a.isEmpty({});
a.isEmpty({a: 1});
答案 1 :(得分:1)
Typescript在以下条件下编译失败:
Person
基本上Sex
无法转换为Object literal may only specify known properties, and 'a' does not exist in type 'string | object | any[]'.
类型。
你可以这样做:
{ a: 1 }
编辑:在看了docs之后,可能会解释为:
联盟类型在这里可能有点棘手,但它需要一点直觉才能习惯。如果值的类型为A | B,我们只知道它有A和B都有的成员。在这个例子中,Bird有一个名为fly的成员。我们无法确定变量是否为Bird |鱼有飞法。如果变量在运行时确实是Fish,则调用pet.fly()将失败。
答案 2 :(得分:1)
您可以通过添加其他签名轻松解决此问题:
interface A {
isEmpty(x: any[]): boolean;
isEmpty(x: string | object): boolean;
isEmptyObject(x: object): boolean;
}
a.isEmpty({ a: 1 }); // fine now
我不认为这是一个错误,如果有任何错误,那么错误信息并不是非常有用。
我认为发生的事情是你可以在任何原始类型的联合中使用object
而没有问题(在你的情况下),但是一旦你引入了非原始类型,那么你就会得到错误,例如:
isEmpty(x: string | object | Map<string, string>): boolean;
会导致同样的错误。
object
(这是任何不是原始的)和另一个非原始类型的联合可能导致一种无法匹配的类型,并且编译器会感到困惑。
欢迎您在这个案例中打开一个新问题,如果您这样做,请在此处分享链接,我想看看他们说了什么。