{"record":{"id":"35e7ff6479da1946","repo":"angular/angular","slug":"unsupported-property-access-for-type-reference-35e7ff","errorCode":null,"errorMessage":"Unsupported property access for type reference: ${expression.name.text}","messagePattern":"Unsupported property access for type reference: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/compiler-cli/src/ngtsc/translator/src/typescript_ast_factory.ts","lineNumber":551,"sourceCode":"        comment.toString(),\n        comment.trailingNewline,\n      );\n    } else {\n      for (const line of comment.toString().split('\\n')) {\n        ts.addSyntheticLeadingComment(statement, commentKind, line, comment.trailingNewline);\n      }\n    }\n  }\n}\n\nfunction getEntityTypeFromExpression(expression: ts.Expression): ts.EntityName {\n  if (ts.isIdentifier(expression)) {\n    return expression;\n  }\n  if (ts.isPropertyAccessExpression(expression)) {\n    const left = getEntityTypeFromExpression(expression.expression);\n    if (!ts.isIdentifier(expression.name)) {\n      throw new Error(`Unsupported property access for type reference: ${expression.name.text}`);\n    }\n    return ts.factory.createQualifiedName(left, expression.name);\n  }\n  throw new Error(`Unsupported expression for type reference: ${ts.SyntaxKind[expression.kind]}`);\n}\n","sourceCodeStart":533,"sourceCodeEnd":557,"githubUrl":"https://github.com/angular/angular/blob/51cb07e98081ab7e4e84a9e0949266a8e19cca84/packages/compiler-cli/src/ngtsc/translator/src/typescript_ast_factory.ts#L533-L557","documentation":"Thrown by the compiler's TypeScriptAstFactory helper getEntityTypeFromExpression while converting an expression into an EntityName (identifier or dotted qualified name) for a type reference. When the expression is a property access, its member must be a plain identifier; the only TS nodes with a non-identifier 'name' on a property access are private identifiers, so in practice this means a '#private' member was used in a type-entity position.","triggerScenarios":"Referencing a private class member like Class.#member anywhere Angular must turn an expression into a type reference — e.g. typeof SomeClass.#constant or namespace-qualified symbols built through property access chains during JIT/AST emission.","commonSituations":"Adopting ECMAScript private fields and then referencing them in decorator or type metadata Angular processes; code generators that emit property-access chains and accidentally include private names.","solutions":["Remove the '#' reference: use the public counterpart or export a dedicated type/class for the thing being referenced.","If the member must stay private, expose a public constant or type alias and reference that instead.","If generating code, restrict emitted entity names to identifiers and dotted public property accesses."],"exampleFix":"// before\nexport class Registry { static #impl = {...}; }\ntype Impl = typeof Registry.#impl; // '#impl' is a PrivateIdentifier, not an Identifier\n\n// after\nexport class Registry { static impl = {...}; }\ntype Impl = typeof Registry.impl;","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"import ts from 'typescript';\n/** true iff expr can become an EntityName (identifier or dotted public property access) */\nfunction isEntityNameExpression(expr: ts.Expression): boolean {\n  if (ts.isIdentifier(expr)) return true;\n  return (\n    ts.isPropertyAccessExpression(expr) &&\n    ts.isIdentifier(expr.name) && // rejects PrivateIdentifier '#x'\n    isEntityNameExpression(expr.expression)\n  );\n}","tryCatchPattern":null,"preventionTips":["Do not reference '#private' members in any position Angular converts to a type reference.","Expose public constants/types for anything metadata must name.","Run isEntityNameExpression in code generators before emitting type references."],"tags":["angular","compiler","typescript","private-identifier","ast-factory"],"backgroundTag":"angular-unsupported-type-expression","analyzedSha":"51cb07e98081ab7e4e84a9e0949266a8e19cca84","analyzedAt":"2026-08-22T07:04:54.531Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}