换句话说,我需要一个恰好代表以下条件的类型:
batchObj !== null &&
typeof batchObj === "object" &&
Array.isArray(batchObj) === false
我曾经使用这种类型谓词函数,直到我注意到{ [key: string]: any }
包括数组:
function isObject(obj: unknown): obj is { [key: string]: any } {
return (
obj !== null && typeof obj === "object" && Array.isArray(obj) === false
);
}
这个问题真的比我想的更难回答。
TypeScript没有真正的否定类型,类似于not X
,意思是";除了X
之外的任何东西";。在microsoft/TypeScript#29317上有一个实验性的pull请求,它是在那里实现的,但它还没有,也可能永远不会合并到主语言中。因此,不存在完全映射到object & not Array<any>
的特定类型。
相反,有各种类型的解决方法。我能想到的最简单的一个是想出一个特定的类型,数组不可分配给它,但大多数其他对象类型都可分配给。例如:
type NonArrayObject = object & { [k: string]: any; forEach?: undefined }
这里我们说的是,NonArrayObject
必须是非基元(object
(,它可以是任何string
键的任何值,,但名为forEach
的属性必须是丢失的或undefined
。这非常接近你想要的:
let nonArrayObject: NonArrayObject;
nonArrayObject = null; // error
nonArrayObject = "oops"; // error
nonArrayObject = {}; // okay
nonArrayObject = { a: 1, b: 2, c: "" }; // okay
nonArrayObject = [1, 2, 3]; // error
当然,作为一种变通方法,它并不完美。也许您真的想允许forEach
属性?
nonArrayObject = { forEach: 123 }; // error!
数组有各种各样的方法和属性,也许你可以找到一个你宁愿声明为禁止使用的方法。也许push
?
type NonArrayObject = object & { [k: string]: any; push?: undefined }
还是lastIndexOf
?
type NonArrayObject = object & { [k: string]: any; lastIndexOf?: undefined }
没有?你需要允许所有可能的密钥?如果我们允许forEach
,但要求它是非函数(注意not Function
也不存在(,该怎么办?
type NonArrayObject = object & {
[k: string]: any;
forEach?: undefined | string | number | boolean | null | { call?: never }
}
等等,等等。务实地说,只要你能识别出一些具体的"非数组对象";类型,你可以使用它。就我个人而言,我从未需要过具有forEach
属性的非数组对象,所以最初的解决方法是我继续的方式。
这至少适用于类型保护功能的true
情况:
declare function isObject(obj: unknown): obj is NonArrayObject;
const obj = Math.random() < 0.5 ? { a: 1, b: 2, c: 3 } : [1, 2, 3];
if (isObject(obj)) {
console.log(obj.b.toFixed(2)); // okay
}
另一种解决方法是放弃特定类型,转而使用泛型类型。例如,您可以使用下面的通用isObject
定义,我认为它将按照您的预期运行:
function isObject2<T>(obj: T | any[]): obj is T {
return (
obj !== null && typeof obj === "object" && Array.isArray(obj) === false
);
}
if (isObject2(obj)) {
console.log(obj.b.toFixed(2));
} else {
console.log(obj.join(","));
}
它使用从并集类型T | any[]
到T
的推断来从该类型的域中隐式地移除any[]
。类似:
function isObject3<T>(obj: T): obj is Exclude<T, any[]> {
return (
obj !== null && typeof obj === "object" && Array.isArray(obj) === false
);
}
if (isObject3(obj)) {
console.log(obj.b.toFixed(2));
} else {
console.log(obj.join(","));
}
使用CCD_ 21实用程序类型将CCD_。
到代码的游乐场链接