diff --git a/packages/aws-cdk-lib/core/lib/tag-manager.ts b/packages/aws-cdk-lib/core/lib/tag-manager.ts index 091a275d0a9ee..a18a26420ee5d 100644 --- a/packages/aws-cdk-lib/core/lib/tag-manager.ts +++ b/packages/aws-cdk-lib/core/lib/tag-manager.ts @@ -303,7 +303,7 @@ export class TagManager { */ public static isTaggable(construct: any): construct is ITaggable { const tags = (construct as any).tags; - return tags && typeof tags === 'object' && (tags as any)[TAG_MANAGER_SYM]; + return tags !== undefined && tags !== null && typeof tags === 'object' && (tags as any)[TAG_MANAGER_SYM]; } /** diff --git a/packages/aws-cdk-lib/core/test/tag-manager.test.ts b/packages/aws-cdk-lib/core/test/tag-manager.test.ts index 86641a7a8af20..16a5c4858e019 100644 --- a/packages/aws-cdk-lib/core/test/tag-manager.test.ts +++ b/packages/aws-cdk-lib/core/test/tag-manager.test.ts @@ -1,3 +1,5 @@ +import { Construct } from 'constructs'; +import * as cdk from '../../../aws-cdk-lib'; import { TagType } from '../lib/cfn-resource'; import { TagManager } from '../lib/tag-manager'; @@ -225,4 +227,39 @@ describe('tag manager', () => { expect(true).toEqual(mgr.applyTagAspectHere(['AWS::Fake::Resource'], [])); expect(false).toEqual(mgr.applyTagAspectHere(['AWS::Wrong::Resource'], [])); }); + + test('isTaggable function works as expected', () => { + const app = new cdk.App(); + const taggableConstruct = new TaggableConstruct(app, 'MyConstruct'); + const nonTaggableConstruct = new NonTaggableConstruct(app, 'NonTaggableConstruct'); + + // Assert that isTaggable returns true for a taggable construct + expect(TagManager.isTaggable(taggableConstruct)).toEqual(true); + + // Assert that isTaggable returns false (not undefined) for a non-taggable construct + expect(TagManager.isTaggable(nonTaggableConstruct)).not.toEqual(undefined); + expect(TagManager.isTaggable(nonTaggableConstruct)).toEqual(false); + }); }); + +// `Stack` extends ITaggable so this construct is Taggable by default +class TaggableConstruct extends cdk.Stack { + constructor(scope: Construct, id: string) { + super(scope, id); + new cdk.CfnResource(this, 'Resource', { + type: 'Whatever::The::Type', + properties: { + Tags: this.tags.renderedTags, + }, + }); + } +} + +// Simple Construct that does not extend ITaggable +class NonTaggableConstruct extends Construct { + public readonly id: string; + constructor(scope: Construct, id: string) { + super(scope, id); + this.id = id; + } +} \ No newline at end of file