diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts index a0553d2b78..85880d8e74 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/dynamic.ts @@ -32,7 +32,8 @@ export const enum DynamicValueReason { /** * An external reference could not be resolved to a value which can be evaluated. - * (E.g. a call expression for a function declared in `.d.ts`.) + * For example a call expression for a function declared in `.d.ts`, or accessing native globals + * such as `window`. */ EXTERNAL_REFERENCE, diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts index 80005e48a0..56b9ac70c0 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/src/interpreter.ts @@ -11,6 +11,7 @@ import * as ts from 'typescript'; import {Reference} from '../../imports'; import {OwningModule} from '../../imports/src/references'; import {Declaration, ReflectionHost} from '../../reflection'; +import {isDeclaration} from '../../util/src/typescript'; import {ArrayConcatBuiltinFn, ArraySliceBuiltinFn} from './builtin'; import {DynamicValue} from './dynamic'; @@ -361,12 +362,15 @@ export class StaticInterpreter { } } return value; + } else if (isDeclaration(ref)) { + return DynamicValue.fromDynamicInput( + node, DynamicValue.fromExternalReference(ref, lhs as Reference)); } } else if (lhs instanceof DynamicValue) { return DynamicValue.fromDynamicInput(node, lhs); - } else { - throw new Error(`Invalid dot property access: ${lhs} dot ${rhs}`); } + + return DynamicValue.fromUnknown(node); } private visitCallExpression(node: ts.CallExpression, context: Context): ResolvedValue { diff --git a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts index a4a1d5523a..4cf93ea800 100644 --- a/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts +++ b/packages/compiler-cli/src/ngtsc/partial_evaluator/test/evaluator_spec.ts @@ -122,6 +122,20 @@ describe('ngtsc metadata', () => { expect(evaluate(`const x = 3;`, '!!x')).toEqual(true); }); + it('resolves access from external variable declarations as dynamic value', () => { + const value = evaluate('declare const window: any;', 'window.location'); + if (!(value instanceof DynamicValue)) { + return fail(`Should have resolved to a DynamicValue`); + } + expect(value.isFromDynamicInput()).toEqual(true); + expect(value.node.getText()).toEqual('window.location'); + if (!(value.reason instanceof DynamicValue)) { + return fail(`Should have a DynamicValue as reason`); + } + expect(value.reason.isFromExternalReference()).toEqual(true); + expect(value.reason.node.getText()).toEqual('window: any'); + }); + it('imports work', () => { const {program} = makeProgram([ {name: 'second.ts', contents: 'export function foo(bar) { return bar; }'},