From b6557c098811208cfb4f311422bb8110c5a26ffa Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 4 Dec 2020 13:50:37 +0100 Subject: [PATCH] core-api: update ApiFactory type to correctly infer API type and disallow mismatched implementations --- .changeset/calm-icons-jump.md | 23 +++++++++++++++++++ .../src/apis/system/ApiFactoryRegistry.ts | 10 ++++---- packages/core-api/src/apis/system/helpers.ts | 15 ++++++------ packages/core-api/src/apis/system/types.ts | 16 +++++++++---- packages/dev-utils/src/devApp/render.tsx | 8 ++++--- 5 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 .changeset/calm-icons-jump.md diff --git a/.changeset/calm-icons-jump.md b/.changeset/calm-icons-jump.md new file mode 100644 index 0000000000..16054a80e6 --- /dev/null +++ b/.changeset/calm-icons-jump.md @@ -0,0 +1,23 @@ +--- +'@backstage/core-api': patch +'@backstage/dev-utils': patch +--- + +Update ApiFactory type to correctly infer API type and disallow mismatched implementations. + +This fixes for example the following code: + +```ts +interface MyApi { + myMethod(): void +} + +const myApiRef = createApiRef({...}); + +createApiFactory({ + api: myApiRef, + deps: {}, + // This should've caused an error, since the empty object does not fully implement MyApi + factory: () => ({}), +}) +``` diff --git a/packages/core-api/src/apis/system/ApiFactoryRegistry.ts b/packages/core-api/src/apis/system/ApiFactoryRegistry.ts index 556f63589c..9d9b058eac 100644 --- a/packages/core-api/src/apis/system/ApiFactoryRegistry.ts +++ b/packages/core-api/src/apis/system/ApiFactoryRegistry.ts @@ -55,9 +55,9 @@ export class ApiFactoryRegistry implements ApiFactoryHolder { * A factory will not be added to the registry if there is already * an existing factory with the same or higher priority. */ - register( + register( scope: ApiFactoryScope, - factory: ApiFactory, + factory: ApiFactory, ) { const priority = ScopePriority[scope]; const existing = this.factories.get(factory.api); @@ -69,12 +69,14 @@ export class ApiFactoryRegistry implements ApiFactoryHolder { return true; } - get(api: ApiRef): ApiFactory | undefined { + get( + api: ApiRef, + ): ApiFactory | undefined { const tuple = this.factories.get(api); if (!tuple) { return undefined; } - return tuple.factory as ApiFactory; + return tuple.factory as ApiFactory; } getAllApis(): Set { diff --git a/packages/core-api/src/apis/system/helpers.ts b/packages/core-api/src/apis/system/helpers.ts index 0ccd0cdb80..cabff73060 100644 --- a/packages/core-api/src/apis/system/helpers.ts +++ b/packages/core-api/src/apis/system/helpers.ts @@ -25,18 +25,19 @@ export function createApiFactory< Api, Impl extends Api, Deps extends { [name in string]: unknown } ->(factory: ApiFactory): ApiFactory; -export function createApiFactory( +>(factory: ApiFactory): ApiFactory; +export function createApiFactory( api: ApiRef, - instance: Api, -): ApiFactory; + instance: Impl, +): ApiFactory; export function createApiFactory< Api, + Impl extends Api, Deps extends { [name in string]: unknown } >( - factory: ApiFactory | ApiRef, - instance?: Api, -): ApiFactory { + factory: ApiFactory | ApiRef, + instance?: Impl, +): ApiFactory { if ('id' in factory) { return { api: factory, diff --git a/packages/core-api/src/apis/system/types.ts b/packages/core-api/src/apis/system/types.ts index b0c19e551c..6234a55c71 100644 --- a/packages/core-api/src/apis/system/types.ts +++ b/packages/core-api/src/apis/system/types.ts @@ -34,16 +34,24 @@ export type ApiHolder = { get(api: ApiRef): T | undefined; }; -export type ApiFactory = { +export type ApiFactory< + Api, + Impl extends Api, + Deps extends { [name in string]: unknown } +> = { api: ApiRef; deps: TypesToApiRefs; - factory(deps: Deps): Api; + factory(deps: Deps): Impl; }; -export type AnyApiFactory = ApiFactory; +export type AnyApiFactory = ApiFactory< + unknown, + unknown, + { [key in string]: unknown } +>; export type ApiFactoryHolder = { get( api: ApiRef, - ): ApiFactory | undefined; + ): ApiFactory | undefined; }; diff --git a/packages/dev-utils/src/devApp/render.tsx b/packages/dev-utils/src/devApp/render.tsx index cca3470f3f..869de01024 100644 --- a/packages/dev-utils/src/devApp/render.tsx +++ b/packages/dev-utils/src/devApp/render.tsx @@ -56,9 +56,11 @@ class DevAppBuilder { /** * Register an API factory to add to the app */ - registerApi( - factory: ApiFactory, - ): DevAppBuilder { + registerApi< + Api, + Impl extends Api, + Deps extends { [name in string]: unknown } + >(factory: ApiFactory): DevAppBuilder { this.apis.push(factory); return this; }