The rule ban-types of newest @typescript-eslint/ban-types disallows object type as default.
I need to refactor my type analyzing functions according this rule.
I understand that TypeScript-ESLint is not source of truth, but wherever I follow to ban-types or violate it, I need to comprehend my decision.
function isNonNullObject(potentialObject: unknown): potentialObject is object {
return typeof potentialObject === "object" && potentialObject !== null;
}
function isNonEmptyObject(potentialObject: unknown): potentialObject is object {
if (typeof potentialObject !== "object" || potentialObject === null) {
return false;
}
return Object.entries(potentialObject as {[key: string]: unknown}).length > 0;
}
function isEmptyObject(potentialObject: unknown): potentialObject is object {
if (typeof potentialObject !== "object" || potentialObject === null) {
return false;
}
return Object.entries(potentialObject as {[key: string]: unknown}).length === 0;
}
The basic usage of this function external data analysis (from API or files):
if (isNonNullObject(data)) {
throw new Error("The data is invalid; object expected.");
}
Should I replace object to other type in this case, or exclusively here object is allowable?
Usage example: data fetching
In real projects, data analyzing functionality is being wrapped to special utility, but it's the concept as below:
type ValidResponseData = {
products: Array<Products>;
productsCount: number;
};
@Component
class ProductsListPage extends Vue {
private products: Array<Products> = [];
private productsCount: number = 0;
private async created(): Promise<void> {
try {
// We must not trust to external data, so it's 'unknown'
const responseData: unknown = await ProductFetchingAPI.fetchAllProducts();
if (!isNonNullObject(responseData)) {
throw new Error(
`The response data data is invalid: non-null object expected, real type: ${typeof responseData},` +
`, value: ${responseData}.`
);
}
// Below checks are meaningless if "responseData" is not object.
if (!Object.prototype.hasOwnProperty.call(responseData, "products")) {
throw new Error(
"Expected that response data has 'products' property but it's missing".
);
}
if (!Object.prototype.hasOwnProperty.call(responseData, "productsCount")) {
throw new Error(
"Expected that response data has 'productsCount' property but it's missing".
);
}
// 'products' and 'productsCount' analysis ....
const validResponseData: ValidResponseData = responseData as ValidResponseData;
this.products = validResponseData.products;
this.productsCount = validResponseData.productsCount;
} catch (error) {
NotificationBarService.displayNotificationBar({
type: NotificationBarService.NotificationsTypes.error,
originalError: error,
text: "Failed to fetch products."
});
}
}
}
Usage example: data analyze from file
const rawData: unknown = /* parse data from the file by appropriate library ... */;
if (!isNonNullObject(rawData)) {
throw new Error(
`The file content is invalid: non-null object expected, real type: ${typeof rawData},` +
`, value: ${rawData}.`
);
}
// Without isNonNullObject(rawData), we can not execute below loop
for (const value of Object.entires(rawData)) {
// check each property
}