refactor: use unknown on component ref type

Co-authored-by: Philipp Hugenroth <philipph@spotify.com>
Co-authored-by: Fredrik Adelöw <freben@gmail.com>
Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com>
Signed-off-by: Camila Belo <camilaibs@gmail.com>
This commit is contained in:
Camila Belo
2023-11-30 13:08:45 +01:00
parent 951decd2ef
commit e5b00a94e6
9 changed files with 75 additions and 79 deletions
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { ComponentType } from 'react';
import { ComponentRef, ComponentsApi } from '@backstage/frontend-plugin-api';
/**
@@ -22,13 +23,13 @@ import { ComponentRef, ComponentsApi } from '@backstage/frontend-plugin-api';
* @internal
*/
export class DefaultComponentsApi implements ComponentsApi {
#components: Map<ComponentRef<any>, any>;
#components: Map<ComponentRef<any>, ComponentType<any>>;
constructor(components: Map<ComponentRef<any>, any>) {
this.#components = components;
}
getComponent<T>(ref: ComponentRef<T>): T {
getComponent<T extends {}>(ref: ComponentRef<T>): ComponentType<T> {
const impl = this.#components.get(ref);
if (!impl) {
throw new Error(`No implementation found for component ref ${ref}`);
+27 -29
View File
@@ -286,7 +286,7 @@ export type CommonAnalyticsContext = {
};
// @public (undocumented)
export type ComponentRef<T> = {
export type ComponentRef<T extends {} = {}> = {
id: string;
T: T;
};
@@ -294,7 +294,7 @@ export type ComponentRef<T> = {
// @public
export interface ComponentsApi {
// (undocumented)
getComponent<T>(ref: ComponentRef<T>): T;
getComponent<T extends {}>(ref: ComponentRef<T>): ComponentType<T>;
}
// @public
@@ -321,29 +321,29 @@ export interface ConfigurableExtensionDataRef<
}
// @public (undocumented)
export type CoreBootErrorPageComponent = ComponentType<
PropsWithChildren<{
step: 'load-config' | 'load-chunk';
error: Error;
}>
>;
export type CoreBootErrorPageProps = PropsWithChildren<{
step: 'load-config' | 'load-chunk';
error: Error;
}>;
// @public (undocumented)
export const coreComponentsRefs: {
progress: ComponentRef<CoreProgressComponent>;
bootErrorPage: ComponentRef<CoreBootErrorPageComponent>;
notFoundErrorPage: ComponentRef<CoreNotFoundErrorPageComponent>;
errorBoundaryFallback: ComponentRef<CoreErrorBoundaryFallbackComponent>;
progress: ComponentRef<{
children?: ReactNode;
}>;
bootErrorPage: ComponentRef<CoreBootErrorPageProps>;
notFoundErrorPage: ComponentRef<{
children?: ReactNode;
}>;
errorBoundaryFallback: ComponentRef<CoreErrorBoundaryFallbackProps>;
};
// @public (undocumented)
export type CoreErrorBoundaryFallbackComponent = ComponentType<
PropsWithChildren<{
plugin?: BackstagePlugin;
error: Error;
resetError: () => void;
}>
>;
export type CoreErrorBoundaryFallbackProps = PropsWithChildren<{
plugin?: BackstagePlugin;
error: Error;
resetError: () => void;
}>;
// @public (undocumented)
export const coreExtensionData: {
@@ -356,20 +356,18 @@ export const coreExtensionData: {
logoElements: ConfigurableExtensionDataRef<LogoElements, {}>;
component: ConfigurableExtensionDataRef<
{
ref: ComponentRef<ComponentType<any>>;
impl: ComponentType<any>;
ref: ComponentRef;
impl: ComponentType;
},
{}
>;
};
// @public (undocumented)
export type CoreNotFoundErrorPageComponent = ComponentType<
PropsWithChildren<{}>
>;
export type CoreNotFoundErrorPageProps = PropsWithChildren<{}>;
// @public (undocumented)
export type CoreProgressComponent = ComponentType<PropsWithChildren<{}>>;
export type CoreProgressProps = PropsWithChildren<{}>;
// @public (undocumented)
export function createApiExtension<
@@ -399,11 +397,11 @@ export { createApiRef };
// @public (undocumented)
export function createComponentExtension<
TRef extends ComponentRef<any>,
TProps extends {},
TConfig extends {},
TInputs extends AnyExtensionInputMap,
>(options: {
ref: TRef;
ref: ComponentRef<TProps>;
name?: string;
disabled?: boolean;
inputs?: TInputs;
@@ -413,13 +411,13 @@ export function createComponentExtension<
lazy: (values: {
config: TConfig;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<TRef['T']>;
}) => Promise<ComponentType<TProps>>;
}
| {
sync: (values: {
config: TConfig;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => TRef['T'];
}) => ComponentType<TProps>;
};
}): ExtensionDefinition<TConfig>;
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { ComponentType } from 'react';
import { createApiRef } from '@backstage/core-plugin-api';
import { ComponentRef } from '../../components';
@@ -24,7 +25,7 @@ import { ComponentRef } from '../../components';
*/
export interface ComponentsApi {
// TODO: Should component refs also provide the default implementation so that we're guaranteed to get a component?
getComponent<T>(ref: ComponentRef<T>): T;
getComponent<T extends {}>(ref: ComponentRef<T>): ComponentType<T>;
}
/**
@@ -15,20 +15,20 @@
*/
import {
CoreBootErrorPageComponent,
CoreErrorBoundaryFallbackComponent,
CoreNotFoundErrorPageComponent,
CoreProgressComponent,
CoreBootErrorPageProps,
CoreErrorBoundaryFallbackProps,
CoreNotFoundErrorPageProps,
CoreProgressProps,
} from '../types';
/** @public */
export type ComponentRef<T> = {
export type ComponentRef<T extends {} = {}> = {
id: string;
T: T;
};
/** @public */
export function createComponentRef<T>(options: {
export function createComponentRef<T extends {} = {}>(options: {
id: string;
}): ComponentRef<T> {
const { id } = options;
@@ -37,22 +37,22 @@ export function createComponentRef<T>(options: {
} as ComponentRef<T>;
}
const coreProgressComponentRef = createComponentRef<CoreProgressComponent>({
const coreProgressComponentRef = createComponentRef<CoreProgressProps>({
id: 'core.components.progress',
});
const coreBootErrorPageComponentRef =
createComponentRef<CoreBootErrorPageComponent>({
createComponentRef<CoreBootErrorPageProps>({
id: 'core.components.bootErrorPage',
});
const coreNotFoundErrorPageComponentRef =
createComponentRef<CoreNotFoundErrorPageComponent>({
createComponentRef<CoreNotFoundErrorPageProps>({
id: 'core.components.notFoundErrorPage',
});
const coreErrorBoundaryFallbackComponentRef =
createComponentRef<CoreErrorBoundaryFallbackComponent>({
createComponentRef<CoreErrorBoundaryFallbackProps>({
id: 'core.components.errorBoundaryFallback',
});
@@ -14,13 +14,13 @@
* limitations under the License.
*/
import React, { Component, PropsWithChildren } from 'react';
import React, { Component, ComponentType, PropsWithChildren } from 'react';
import { BackstagePlugin } from '../wiring';
import { CoreErrorBoundaryFallbackComponent } from '../types';
import { CoreErrorBoundaryFallbackProps } from '../types';
type ErrorBoundaryProps = PropsWithChildren<{
plugin?: BackstagePlugin;
fallback: CoreErrorBoundaryFallbackComponent;
fallback: ComponentType<CoreErrorBoundaryFallbackProps>;
}>;
type ErrorBoundaryState = { error?: Error };
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import React, { lazy } from 'react';
import React, { lazy, ComponentType } from 'react';
import {
AnyExtensionInputMap,
ResolvedExtensionInputs,
@@ -27,11 +27,11 @@ import { ExtensionBoundary, ComponentRef } from '../components';
/** @public */
export function createComponentExtension<
TRef extends ComponentRef<any>,
TProps extends {},
TConfig extends {},
TInputs extends AnyExtensionInputMap,
>(options: {
ref: TRef;
ref: ComponentRef<TProps>;
name?: string;
disabled?: boolean;
inputs?: TInputs;
@@ -41,13 +41,13 @@ export function createComponentExtension<
lazy: (values: {
config: TConfig;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<TRef['T']>;
}) => Promise<ComponentType<TProps>>;
}
| {
sync: (values: {
config: TConfig;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => TRef['T'];
}) => ComponentType<TProps>;
};
}) {
return createExtension({
@@ -62,15 +62,17 @@ export function createComponentExtension<
component: coreExtensionData.component,
},
factory({ config, inputs, node }) {
let ExtensionComponent: TRef['T'];
let ExtensionComponent: ComponentType<TProps>;
if ('sync' in options.component) {
ExtensionComponent = options.component.sync({ config, inputs });
} else {
const loader = options.component.lazy({ config, inputs });
const lazyLoader = options.component.lazy;
ExtensionComponent = lazy(() =>
loader.then(component => ({ default: component })),
);
lazyLoader({ config, inputs }).then(component => ({
default: component,
})),
) as unknown as ComponentType<TProps>;
}
return {
@@ -78,7 +80,7 @@ export function createComponentExtension<
ref: options.ref,
impl: props => (
<ExtensionBoundary node={node}>
<ExtensionComponent {...props} />
<ExtensionComponent {...(props as TProps)} />
</ExtensionBoundary>
),
},
+4 -4
View File
@@ -31,8 +31,8 @@ export * from './apis/system';
export * from './wiring';
export type {
CoreProgressComponent,
CoreBootErrorPageComponent,
CoreNotFoundErrorPageComponent,
CoreErrorBoundaryFallbackComponent,
CoreProgressProps,
CoreBootErrorPageProps,
CoreNotFoundErrorPageProps,
CoreErrorBoundaryFallbackProps,
} from './types';
+12 -18
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { ComponentType, PropsWithChildren } from 'react';
import { PropsWithChildren } from 'react';
import { BackstagePlugin } from './wiring';
// TODO(Rugvip): This might be a quite useful utility type, maybe add to @backstage/types?
@@ -25,26 +25,20 @@ import { BackstagePlugin } from './wiring';
export type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
/** @public */
export type CoreProgressComponent = ComponentType<PropsWithChildren<{}>>;
export type CoreProgressProps = PropsWithChildren<{}>;
/** @public */
export type CoreBootErrorPageComponent = ComponentType<
PropsWithChildren<{
step: 'load-config' | 'load-chunk';
error: Error;
}>
>;
export type CoreBootErrorPageProps = PropsWithChildren<{
step: 'load-config' | 'load-chunk';
error: Error;
}>;
/** @public */
export type CoreNotFoundErrorPageComponent = ComponentType<
PropsWithChildren<{}>
>;
export type CoreNotFoundErrorPageProps = PropsWithChildren<{}>;
/** @public */
export type CoreErrorBoundaryFallbackComponent = ComponentType<
PropsWithChildren<{
plugin?: BackstagePlugin;
error: Error;
resetError: () => void;
}>
>;
export type CoreErrorBoundaryFallbackProps = PropsWithChildren<{
plugin?: BackstagePlugin;
error: Error;
resetError: () => void;
}>;
@@ -47,7 +47,7 @@ export const coreExtensionData = {
theme: createExtensionDataRef<AppTheme>('core.theme'),
logoElements: createExtensionDataRef<LogoElements>('core.logos'),
component: createExtensionDataRef<{
ref: ComponentRef<ComponentType<any>>;
impl: ComponentType<any>;
ref: ComponentRef;
impl: ComponentType;
}>('component.ref'),
};