Common TypeScript types used within Backstage for JSON handling and reactive programming patterns
99
Pending
Does it follow best practices?
Impact
99%
1.67xAverage score across 5 eval scenarios
Pending
The risk profile of this skill
Backstage Types provides essential TypeScript type definitions that serve as common building blocks throughout the Backstage ecosystem. It includes foundational JSON types for type-safe handling of JSON data structures and Observable types for reactive programming patterns following the TC39 Observable proposal.
npm install @backstage/typesimport { JsonValue, JsonObject, JsonArray, JsonPrimitive } from "@backstage/types";
import { Observable, Observer, Subscription } from "@backstage/types";For CommonJS:
const { JsonValue, JsonObject, JsonArray, JsonPrimitive } = require("@backstage/types");
const { Observable, Observer, Subscription } = require("@backstage/types");import { JsonValue, JsonObject, Observable, Observer } from "@backstage/types";
// Type-safe JSON handling
const config: JsonObject = {
name: "my-plugin",
enabled: true,
settings: {
timeout: 5000,
retries: 3
}
};
const data: JsonValue = ["item1", "item2", { nested: true }];
// Observable pattern usage
const observer: Observer<string> = {
next: (value) => console.log(`Received: ${value}`),
error: (err) => console.error(`Error: ${err.message}`),
complete: () => console.log("Stream completed")
};
// Subscribe to an observable (using compatible implementation like zen-observable)
const subscription: Subscription = someObservable.subscribe(observer);
// Clean up subscription
subscription.unsubscribe();Backstage Types is designed as a foundational layer providing standardized type definitions across the Backstage ecosystem:
Provides comprehensive type definitions for all JSON value types, enabling type-safe JSON handling across frontend and backend Backstage components.
/** A type representing all allowed JSON primitive values */
type JsonPrimitive = number | string | boolean | null;
/** A type representing all allowed JSON object values */
type JsonObject = { [key in string]?: JsonValue };
/** A type representing all allowed JSON array values */
interface JsonArray extends Array<JsonValue> {}
/** A type representing all allowed JSON values */
type JsonValue = JsonObject | JsonArray | JsonPrimitive;Usage Examples:
import { JsonValue, JsonObject, JsonPrimitive } from "@backstage/types";
// Type-safe API responses
function processApiResponse(response: JsonValue): void {
if (typeof response === "object" && response !== null && !Array.isArray(response)) {
// TypeScript knows this is JsonObject
const obj = response as JsonObject;
console.log(obj.status);
}
}
// Configuration handling
interface PluginConfig extends JsonObject {
name: string;
version: string;
settings?: JsonObject;
}
const config: PluginConfig = {
name: "my-backstage-plugin",
version: "1.0.0",
settings: {
enabled: true,
timeout: 30000
}
};
// Primitive value handling
function validatePrimitive(value: unknown): JsonPrimitive | null {
if (typeof value === "string" || typeof value === "number" ||
typeof value === "boolean" || value === null) {
return value;
}
return null;
}Provides standardized Observable types following the TC39 Observable proposal, enabling consistent reactive programming patterns across Backstage plugins and extensions.
/** Observer interface for consuming an Observable, see TC39 */
type Observer<T> = {
next?(value: T): void;
error?(error: Error): void;
complete?(): void;
};
/** Subscription returned when subscribing to an Observable, see TC39 */
type Subscription = {
/** Cancels the subscription */
unsubscribe(): void;
/** Value indicating whether the subscription is closed */
readonly closed: boolean;
};
/** Observable sequence of values and errors, see TC39 */
type Observable<T> = {
[Symbol.observable](): Observable<T>;
/** Subscribes to this observable to start receiving new values */
subscribe(observer: Observer<T>): Subscription;
subscribe(
onNext?: (value: T) => void,
onError?: (error: Error) => void,
onComplete?: () => void,
): Subscription;
};Usage Examples:
import { Observable, Observer, Subscription } from "@backstage/types";
// Creating an observer
const dataObserver: Observer<string> = {
next: (value: string) => {
console.log(`Processing data: ${value}`);
},
error: (error: Error) => {
console.error(`Data processing failed: ${error.message}`);
},
complete: () => {
console.log("Data stream completed");
}
};
// Using with zen-observable (common implementation)
import ZenObservable from 'zen-observable';
const observable: Observable<string> = new ZenObservable<string>(
(subscriber: Observer<string>) => {
subscriber.next?.("Hello");
subscriber.next?.("World");
subscriber.complete?.();
}
);
// Subscribe with observer object
const subscription1: Subscription = observable.subscribe(dataObserver);
// Subscribe with callback functions
const subscription2: Subscription = observable.subscribe(
(value) => console.log(`Value: ${value}`),
(error) => console.error(`Error: ${error}`),
() => console.log("Done!")
);
// Cleanup subscriptions
subscription1.unsubscribe();
subscription2.unsubscribe();
// Check subscription status
console.log(`Is closed: ${subscription1.closed}`);The package declares the global Symbol.observable symbol used by the Observable implementation:
declare global {
interface SymbolConstructor {
readonly observable: symbol;
}
}This declaration ensures compatibility with Observable implementations that rely on the well-known symbol, with the actual runtime polyfill typically provided by libraries like zen-observable.
The Observable types include built-in error handling through the Observer.error callback and the subscribe method's onError parameter. When implementing Observable consumers, always handle potential errors:
import { Observer } from "@backstage/types";
const robustObserver: Observer<any> = {
next: (value) => {
try {
// Process value
processValue(value);
} catch (error) {
console.error("Processing error:", error);
}
},
error: (error) => {
// Handle stream errors
console.error("Stream error:", error);
// Optionally attempt recovery or cleanup
},
complete: () => {
console.log("Stream completed successfully");
}
};