From ddc5247f6772e347329d63923d0a9f526916e5ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20Adel=C3=B6w?= Date: Tue, 24 Mar 2026 22:30:56 +0100 Subject: [PATCH] fix(frontend-plugin-api): fix FlattenedMessages type depth for TypeScript 6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure the FlattenedMessages conditional type to check `TMessages[TKey] extends string` directly instead of using an intermediate `infer TValue` pattern, which caused excessive type instantiation depth in TypeScript 6. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Fredrik Adelöw --- .changeset/fix-translation-ref-ts6.md | 5 +++++ .../src/translation/TranslationRef.ts | 20 +++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 .changeset/fix-translation-ref-ts6.md diff --git a/.changeset/fix-translation-ref-ts6.md b/.changeset/fix-translation-ref-ts6.md new file mode 100644 index 0000000000..1662d6c7ea --- /dev/null +++ b/.changeset/fix-translation-ref-ts6.md @@ -0,0 +1,5 @@ +--- +'@backstage/frontend-plugin-api': patch +--- + +Fixed `FlattenedMessages` type to avoid excessive type instantiation depth in TypeScript 6 when using `createTranslationRef` with the `translations` option. diff --git a/packages/frontend-plugin-api/src/translation/TranslationRef.ts b/packages/frontend-plugin-api/src/translation/TranslationRef.ts index 7686e68343..c621ec6d24 100644 --- a/packages/frontend-plugin-api/src/translation/TranslationRef.ts +++ b/packages/frontend-plugin-api/src/translation/TranslationRef.ts @@ -51,16 +51,16 @@ type FlattenedMessages = // final step of flipping this unions around to an intersection by inferring the function parameter. { [TKey in keyof TMessages]: ( - _: TMessages[TKey] extends infer TValue // "local variable" for the value - ? TValue extends AnyNestedMessages - ? FlattenedMessages extends infer TNested // Recurse into nested messages, "local variable" for the result - ? { - [TNestedKey in keyof TNested as `${TKey & string}.${TNestedKey & - string}`]: TNested[TNestedKey]; - } - : never - : { [_ in TKey]: TValue } // Primitive object values are passed through with the same key - : never, + _: TMessages[TKey] extends string + ? { [_ in TKey]: TMessages[TKey] } // String values are leaf nodes, passed through with the same key + : TMessages[TKey] extends AnyNestedMessages + ? FlattenedMessages extends infer TNested // Recurse into nested messages, "local variable" for the result + ? { + [TNestedKey in keyof TNested as `${TKey & string}.${TNestedKey & + string}`]: TNested[TNestedKey]; + } + : never + : { [_ in TKey]: TMessages[TKey] }, // Other primitive values are passed through with the same key, ) => void; // The `[keyof TMessages]` extracts the object values union from our flattened structure, still wrapped up in function parameters. // The `extends (_: infer TIntersection) => void` flips the union to an intersection, at which point we have the correct type.