fixes for TypeScript 5.0

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
Patrik Oldsberg
2023-03-25 15:30:22 +01:00
parent cc0e135cb9
commit 2898b6c8d5
22 changed files with 72 additions and 45 deletions
+8
View File
@@ -0,0 +1,8 @@
---
'@backstage/core-plugin-api': patch
'@backstage/plugin-scaffolder-react': patch
'@backstage/plugin-scaffolder-node': patch
'@backstage/plugin-catalog-react': patch
---
Minor type tweaks for TypeScript 5.0
+2 -2
View File
@@ -15,12 +15,12 @@
*/
import chalk from 'chalk';
import inquirer from 'inquirer';
import inquirer, { Answers } from 'inquirer';
import { AnyFactory, Prompt } from './types';
import * as factories from './factories';
import partition from 'lodash/partition';
function applyPromptMessageTransforms<T>(
function applyPromptMessageTransforms<T extends Answers>(
prompt: Prompt<T>,
transforms: {
message: (msg: string) => string;
+4 -2
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { DistinctQuestion } from 'inquirer';
import { Answers, DistinctQuestion } from 'inquirer';
export interface CreateContext {
/** The package scope to use for new packages */
@@ -37,7 +37,9 @@ export interface CreateContext {
export type AnyOptions = Record<string, string>;
export type Prompt<TOptions> = DistinctQuestion<TOptions> & { name: string };
export type Prompt<TOptions extends Answers> = DistinctQuestion<TOptions> & {
name: string;
};
export interface Factory<TOptions extends AnyOptions> {
/**
@@ -376,7 +376,7 @@ export function Table<T extends object = {}>(props: TableProps<T>) {
const newData = (data as any[]).filter(
el =>
!!Object.entries(selectedFilters)
.filter(([, value]) => !!value.length)
.filter(([, value]) => !!(value as { length?: number }).length)
.every(([key, filterValue]) => {
const fieldValue = extractValueByField(
el,
@@ -91,11 +91,11 @@ export const AnalyticsContext = (options: {
* @param values - Analytics context key/value pairs.
* @internal
*/
export function withAnalyticsContext<P>(
Component: React.ComponentType<P>,
export function withAnalyticsContext<TProps extends {}>(
Component: React.ComponentType<TProps>,
values: AnalyticsContextValue,
) {
const ComponentWithAnalyticsContext = (props: P) => {
const ComponentWithAnalyticsContext = (props: TProps) => {
return (
<AnalyticsContext attributes={values}>
<Component {...props} />
@@ -58,11 +58,11 @@ export function useApi<T>(apiRef: ApiRef<T>): T {
* @param apis - APIs for the context.
* @public
*/
export function withApis<T>(apis: TypesToApiRefs<T>) {
return function withApisWrapper<P extends T>(
WrappedComponent: React.ComponentType<P>,
export function withApis<T extends {}>(apis: TypesToApiRefs<T>) {
return function withApisWrapper<TProps extends T>(
WrappedComponent: React.ComponentType<TProps>,
) {
const Hoc = (props: PropsWithChildren<Omit<P, keyof T>>) => {
const Hoc = (props: PropsWithChildren<Omit<TProps, keyof T>>) => {
const apiHolder = useApiHolder();
const impls = {} as T;
@@ -79,7 +79,7 @@ export function withApis<T>(apis: TypesToApiRefs<T>) {
}
}
return <WrappedComponent {...(props as P)} {...impls} />;
return <WrappedComponent {...(props as TProps)} {...impls} />;
};
const displayName =
WrappedComponent.displayName || WrappedComponent.name || 'Component';
@@ -101,7 +101,9 @@ export class MockStorageApi implements StorageApi {
});
}
observe$<T>(key: string): Observable<StorageValueSnapshot<T>> {
observe$<T extends JsonValue>(
key: string,
): Observable<StorageValueSnapshot<T>> {
return this.observable.filter(({ key: messageKey }) => messageKey === key);
}
@@ -109,7 +111,7 @@ export class MockStorageApi implements StorageApi {
return `${this.namespace}/${encodeURIComponent(key)}`;
}
private notifyChanges<T>(message: StorageValueSnapshot<T>) {
private notifyChanges<T extends JsonValue>(message: StorageValueSnapshot<T>) {
for (const subscription of this.subscribers) {
subscription.next(message);
}
@@ -208,7 +208,7 @@ export function wrapInTestApp(
let wrappedElement: React.ReactElement;
if (Component instanceof Function) {
wrappedElement = <Component />;
wrappedElement = React.createElement(Component as ComponentType);
} else {
wrappedElement = Component as React.ReactElement;
}
@@ -233,7 +233,7 @@ export async function renderInTestApp(
): Promise<RenderResult> {
let wrappedElement: React.ReactElement;
if (Component instanceof Function) {
wrappedElement = <Component />;
wrappedElement = React.createElement(Component as ComponentType);
} else {
wrappedElement = Component as React.ReactElement;
}
@@ -114,8 +114,9 @@ export function EntityAutocompletePicker<
} as Partial<T>);
}, [name, shouldAddFilter, selectedOptions, Filter, updateFilters]);
const filter = filters[name];
if (
(filters[name] && !('values' in filters[name])) ||
(filter && typeof filter === 'object' && !('values' in filter)) ||
!availableOptions.length
) {
return null;
@@ -57,11 +57,14 @@ export function FetchedEntityRefLinks<
error,
} = useAsync(async () => {
const refs = entityRefs.reduce((acc, current) => {
return 'metadata' in current ? acc : [...acc, parseEntityRef(current)];
if (typeof current === 'object' && 'metadata' in current) {
return acc;
}
return [...acc, parseEntityRef(current)];
}, new Array<CompoundEntityRef>());
const pureEntities = entityRefs.filter(
ref => 'metadata' in ref,
ref => typeof ref === 'object' && 'metadata' in ref,
) as Array<Entity>;
return refs.length > 0
@@ -161,8 +161,9 @@ export const EntityListProvider = <EntityFilters extends DefaultEntityFilters>(
const queryParams = Object.keys(requestedFilters).reduce(
(params, key) => {
const filter: EntityFilter | undefined =
requestedFilters[key as keyof EntityFilters];
const filter = requestedFilters[key as keyof EntityFilters] as
| EntityFilter
| undefined;
if (filter?.toQueryValue) {
params[key] = filter.toQueryValue();
}
@@ -70,10 +70,14 @@ function countTriggersPerDay(builds: ReadonlyArray<Build>) {
const values = Object.entries(days).map(([epoch, buildsThisDay]) => {
const datapoint = Object.fromEntries(
triggerReasons
.map(reason => [
reason,
buildsThisDay.filter(build => build.triggeredBy === reason).length,
])
.map(
reason =>
[
reason,
buildsThisDay.filter(build => build.triggeredBy === reason)
.length,
] as const,
)
.filter(([_type, count]) => count > 0),
) as Omit<TriggerReasonsDatapoint, '__epoch'>;
@@ -134,7 +134,7 @@ export const StarredRatingButtons = (props: StarredRatingButtonsProps) => {
return (
<>
{Object.values(FeedbackRatings)
.filter(o => typeof o === 'number')
.filter((o): o is number => typeof o === 'number')
.map(starRating => (
<IconButton
key={starRating}
@@ -73,7 +73,7 @@ export const IssuesList = ({
const filteredRepos = React.useMemo(
() =>
issuesByRepository && activeFilter.length
? activeFilter.reduce(
? activeFilter.reduce<IssuesByRepo>(
(acc, val) => ({
[val]: issuesByRepository[val],
...acc,
@@ -172,8 +172,9 @@ export const PlaylistListProvider = <
const queryParams = Object.keys(requestedFilters).reduce(
(params, key) => {
const filter: PlaylistFilter | undefined =
requestedFilters[key as keyof PlaylistFilters];
const filter = requestedFilters[key as keyof PlaylistFilters] as
| PlaylistFilter
| undefined;
if (filter?.toQueryValue) {
params[key] = filter.toQueryValue();
}
@@ -104,7 +104,7 @@ export class RollbarApi {
);
}
private async get<T>(url: string, accessToken?: string) {
private async get<T extends {}>(url: string, accessToken?: string) {
const fullUrl = buildUrl(url);
if (this.logger) {
@@ -119,7 +119,7 @@ export class RollbarApi {
.then(json => camelcaseKeys<T>(json?.result, { deep: true }));
}
private async getForProject<T>(
private async getForProject<T extends {}>(
url: string,
projectName: string,
useProjectToken = true,
@@ -120,7 +120,7 @@ describe('DefaultWorkflowRunner', () => {
foo: z.number(),
}),
},
}) as TemplateAction<unknown>,
}) as TemplateAction,
);
actionRegistry.register({
@@ -22,8 +22,8 @@ import { JsonObject } from '@backstage/types';
/** @public */
export type TemplateActionOptions<
TActionInput = {},
TActionOutput = {},
TActionInput extends JsonObject = {},
TActionOutput extends JsonObject = {},
TInputSchema extends Schema | z.ZodType = {},
TOutputSchema extends Schema | z.ZodType = {},
> = {
@@ -48,10 +48,18 @@ export const createTemplateAction = <
TOutputParams extends JsonObject = JsonObject,
TInputSchema extends Schema | z.ZodType = {},
TOutputSchema extends Schema | z.ZodType = {},
TActionInput = TInputSchema extends z.ZodType<any, any, infer IReturn>
TActionInput extends JsonObject = TInputSchema extends z.ZodType<
any,
any,
infer IReturn
>
? IReturn
: TInputParams,
TActionOutput = TOutputSchema extends z.ZodType<any, any, infer IReturn>
TActionOutput extends JsonObject = TOutputSchema extends z.ZodType<
any,
any,
infer IReturn
>
? IReturn
: TOutputParams,
>(
+2 -2
View File
@@ -75,8 +75,8 @@ export type ActionContext<
/** @public */
export type TemplateAction<
TActionInput = unknown,
TActionOutput = JsonObject,
TActionInput extends JsonObject = JsonObject,
TActionOutput extends JsonObject = JsonObject,
> = {
id: string;
description?: string;
@@ -64,7 +64,7 @@ export type FieldExtensionOptions<
*/
export interface FieldExtensionComponentProps<
TFieldReturnValue,
TUiOptions extends {} = {},
TUiOptions = unknown,
> extends FieldProps<TFieldReturnValue> {
uiSchema: FieldProps['uiSchema'] & {
'ui:options'?: TUiOptions;
+1 -4
View File
@@ -66,9 +66,6 @@ createDevApp()
<EntityGridItem xs={12} md={6} entity={entity('passed')}>
<EntitySonarQubeCard />
</EntityGridItem>
<EntityGridItem xs={12} entity={entity(undefined)}>
<EntitySonarQubeCard />
</EntityGridItem>
</Grid>
</Content>
</Page>
@@ -79,7 +76,7 @@ createDevApp()
deps: {},
factory: () =>
({
getFindingSummary: async componentKey => {
getFindingSummary: async ({ componentKey }) => {
switch (componentKey) {
case 'error':
throw new Error('Error!');
@@ -59,7 +59,7 @@ export const Content = (props: StackOverflowQuestionsContentProps) => {
return <Typography paragraph>could not load questions</Typography>;
}
const getSecondaryText = (answer_count: Number) =>
const getSecondaryText = (answer_count: number) =>
answer_count > 1 ? `${answer_count} answers` : `${answer_count} answer`;
return (