mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: Stricter typing in type guards (#77809)
* Stricter typing in type guards * create utility isObject fn * better isAlertStateWithReason * better name * restore "data !== undefined"
This commit is contained in:
61
packages/grafana-data/src/types/data.test.ts
Normal file
61
packages/grafana-data/src/types/data.test.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { isObject, isTruthy } from './data';
|
||||
|
||||
describe('isObject', () => {
|
||||
it.each([
|
||||
// [value, expected]
|
||||
|
||||
// These are objects
|
||||
[{}, true],
|
||||
[[], true],
|
||||
[{ a: 1 }, true],
|
||||
[new Date(), true],
|
||||
[new Error(), true],
|
||||
|
||||
// These are not!
|
||||
[parseInt('blabla', 10), false], // NaN
|
||||
[null, false],
|
||||
[undefined, false],
|
||||
[-Infinity, false],
|
||||
[-42, false],
|
||||
[0, false],
|
||||
[-0, false],
|
||||
[42, false],
|
||||
[Infinity, false],
|
||||
['foo', false],
|
||||
[true, false],
|
||||
[Symbol(), false],
|
||||
[() => {}, false],
|
||||
])('should return %p for %p', (input, expected) => {
|
||||
expect(isObject(input)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isTruthy', () => {
|
||||
it.each([
|
||||
// [value, expected]
|
||||
|
||||
// These are truthy
|
||||
[true, true],
|
||||
[-Infinity, true],
|
||||
[-42, true],
|
||||
[42, true],
|
||||
[Infinity, true],
|
||||
['foo', true],
|
||||
[{}, true],
|
||||
[[], true],
|
||||
[() => {}, true],
|
||||
[Symbol(), true],
|
||||
[new Date(), true],
|
||||
|
||||
// These are falsy
|
||||
[false, false],
|
||||
[0, false],
|
||||
[-0, false],
|
||||
['', false],
|
||||
[null, false],
|
||||
[undefined, false],
|
||||
[parseInt('blabla', 10), false], // NaN
|
||||
])('should return %p for %p', (input, expected) => {
|
||||
expect(isTruthy(input)).toBe(expected);
|
||||
});
|
||||
});
|
||||
@@ -213,3 +213,27 @@ export interface DataConfigSource {
|
||||
|
||||
type Truthy<T> = T extends false | '' | 0 | null | undefined ? never : T;
|
||||
export const isTruthy = <T>(value: T): value is Truthy<T> => Boolean(value);
|
||||
|
||||
/**
|
||||
* Serves no runtime purpose - only used to make typescript check a value has been correctly
|
||||
* narrowed to an object
|
||||
*/
|
||||
function identityObject(value: object): object {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility type predicate to check if a value is typeof object, but excludes "null".
|
||||
*
|
||||
* We normally discourage the use of type predicates in favor of just inline typescript narrowing,
|
||||
* but this is a special case to handle null annoyingly being typeof object
|
||||
*/
|
||||
export function isObject(value: unknown): value is object {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
identityObject(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
StandardEditorContext,
|
||||
} from '../field';
|
||||
import { PanelOptionsSupplier } from '../panel/PanelPlugin';
|
||||
import { isObject } from '../types';
|
||||
import { OptionsEditorItem, OptionsUIRegistryBuilder } from '../types/OptionsUIRegistryBuilder';
|
||||
import { FieldConfigEditorProps, FieldConfigPropertyItem, FieldConfigEditorConfig } from '../types/fieldOverrides';
|
||||
import { PanelOptionsEditorConfig, PanelOptionsEditorItem } from '../types/panel';
|
||||
@@ -204,8 +205,8 @@ export class NestedPanelOptionsBuilder<TSub = any> implements OptionsEditorItem<
|
||||
};
|
||||
}
|
||||
|
||||
export function isNestedPanelOptions(item: any): item is NestedPanelOptionsBuilder {
|
||||
return item.id === 'nested-panel-options';
|
||||
export function isNestedPanelOptions(item: unknown): item is NestedPanelOptionsBuilder {
|
||||
return isObject(item) && 'id' in item && item.id === 'nested-panel-options';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user