是否有一个类型表示具有任何属性但不是数组的对象



换句话说,我需要一个恰好代表以下条件的类型:

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_。


到代码的游乐场链接

最新更新