diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 025eeecc30624..6ba0d793501a8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4110,8 +4110,10 @@ namespace ts { return getMergedSymbol(symbol && (symbol.flags & SymbolFlags.ExportValue) !== 0 && symbol.exportSymbol || symbol); } - function symbolIsValue(symbol: Symbol): boolean { - return !!(symbol.flags & SymbolFlags.Value || symbol.flags & SymbolFlags.Alias && resolveAlias(symbol).flags & SymbolFlags.Value && !getTypeOnlyAliasDeclaration(symbol)); + function symbolIsValue(symbol: Symbol, includeTypeOnlyMembers?: boolean): boolean { + return !!( + symbol.flags & SymbolFlags.Value || + symbol.flags & SymbolFlags.Alias && resolveAlias(symbol).flags & SymbolFlags.Value && (includeTypeOnlyMembers || !getTypeOnlyAliasDeclaration(symbol))); } function findConstructorDeclaration(node: ClassLikeDeclaration): ConstructorDeclaration | undefined { @@ -12575,12 +12577,12 @@ namespace ts { * @param type a type to look up property from * @param name a name of property to look up in a given type */ - function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean): Symbol | undefined { + function getPropertyOfType(type: Type, name: __String, skipObjectFunctionPropertyAugment?: boolean, includeTypeOnlyMembers?: boolean): Symbol | undefined { type = getReducedApparentType(type); if (type.flags & TypeFlags.Object) { const resolved = resolveStructuredTypeMembers(type as ObjectType); const symbol = resolved.members.get(name); - if (symbol && symbolIsValue(symbol)) { + if (symbol && symbolIsValue(symbol, includeTypeOnlyMembers)) { return symbol; } if (skipObjectFunctionPropertyAugment) return undefined; @@ -16208,7 +16210,7 @@ namespace ts { // the `exports` lookup process that only looks up namespace members which is used for most type references const mergedResolvedSymbol = getMergedSymbol(resolveSymbol(currentNamespace)); const next = node.isTypeOf - ? getPropertyOfType(getTypeOfSymbol(mergedResolvedSymbol), current.escapedText) + ? getPropertyOfType(getTypeOfSymbol(mergedResolvedSymbol), current.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ true) : getSymbol(getExportsOfSymbol(mergedResolvedSymbol), current.escapedText, meaning); if (!next) { error(current, Diagnostics.Namespace_0_has_no_exported_member_1, getFullyQualifiedName(currentNamespace), declarationNameToString(current)); @@ -28995,9 +28997,9 @@ namespace ts { if (isIdentifier(left) && parentSymbol) { markAliasReferenced(parentSymbol, node); } - return isErrorType(apparentType) ? errorType : apparentType;; + return isErrorType(apparentType) ? errorType : apparentType; } - prop = getPropertyOfType(apparentType, right.escapedText); + prop = getPropertyOfType(apparentType, right.escapedText, /*skipObjectFunctionPropertyAugment*/ false, /*includeTypeOnlyMembers*/ node.kind === SyntaxKind.QualifiedName); } // In `Foo.Bar.Baz`, 'Foo' is not referenced if 'Bar' is a const enum or a module containing only const enums. // `Foo` is also not referenced in `enum FooCopy { Bar = Foo.Bar }`, because the enum member value gets inlined diff --git a/tests/baselines/reference/namespaceImportTypeQuery.errors.txt b/tests/baselines/reference/namespaceImportTypeQuery.errors.txt index 5036215385d45..928882d2b179b 100644 --- a/tests/baselines/reference/namespaceImportTypeQuery.errors.txt +++ b/tests/baselines/reference/namespaceImportTypeQuery.errors.txt @@ -1,4 +1,5 @@ -/b.ts(2,21): error TS2339: Property 'A' does not exist on type 'typeof import("/a")'. +/b.ts(8,3): error TS2322: Type '{ A: any; B: any; }' is not assignable to type 'typeof import("/a")'. + Object literal may only specify known properties, and 'A' does not exist in type 'typeof import("/a")'. ==== /a.ts (0 errors) ==== @@ -9,7 +10,15 @@ ==== /b.ts (1 errors) ==== import * as types from './a'; let A: typeof types.A; - ~ -!!! error TS2339: Property 'A' does not exist on type 'typeof import("/a")'. let B: typeof types.B; + + let t: typeof types = { + // error: while you can ask for `typeof types.A`, + // `typeof types` does not include `A` + A: undefined as any, + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ A: any; B: any; }' is not assignable to type 'typeof import("/a")'. +!!! error TS2322: Object literal may only specify known properties, and 'A' does not exist in type 'typeof import("/a")'. + B: undefined as any, + } \ No newline at end of file diff --git a/tests/baselines/reference/namespaceImportTypeQuery.js b/tests/baselines/reference/namespaceImportTypeQuery.js index 18ea634352165..33746b223b1a6 100644 --- a/tests/baselines/reference/namespaceImportTypeQuery.js +++ b/tests/baselines/reference/namespaceImportTypeQuery.js @@ -9,6 +9,13 @@ export class B {}; import * as types from './a'; let A: typeof types.A; let B: typeof types.B; + +let t: typeof types = { + // error: while you can ask for `typeof types.A`, + // `typeof types` does not include `A` + A: undefined as any, + B: undefined as any, +} //// [a.js] @@ -32,3 +39,9 @@ exports.B = B; exports.__esModule = true; var A; var B; +var t = { + // error: while you can ask for `typeof types.A`, + // `typeof types` does not include `A` + A: undefined, + B: undefined +}; diff --git a/tests/baselines/reference/namespaceImportTypeQuery.symbols b/tests/baselines/reference/namespaceImportTypeQuery.symbols index 9851b31b6b001..30b8694f6022a 100644 --- a/tests/baselines/reference/namespaceImportTypeQuery.symbols +++ b/tests/baselines/reference/namespaceImportTypeQuery.symbols @@ -14,7 +14,9 @@ import * as types from './a'; let A: typeof types.A; >A : Symbol(A, Decl(b.ts, 1, 3)) +>types.A : Symbol(types.A, Decl(a.ts, 1, 13)) >types : Symbol(types, Decl(b.ts, 0, 6)) +>A : Symbol(types.A, Decl(a.ts, 1, 13)) let B: typeof types.B; >B : Symbol(B, Decl(b.ts, 2, 3)) @@ -22,3 +24,18 @@ let B: typeof types.B; >types : Symbol(types, Decl(b.ts, 0, 6)) >B : Symbol(types.B, Decl(a.ts, 1, 18)) +let t: typeof types = { +>t : Symbol(t, Decl(b.ts, 4, 3)) +>types : Symbol(types, Decl(b.ts, 0, 6)) + + // error: while you can ask for `typeof types.A`, + // `typeof types` does not include `A` + A: undefined as any, +>A : Symbol(A, Decl(b.ts, 4, 23)) +>undefined : Symbol(undefined) + + B: undefined as any, +>B : Symbol(B, Decl(b.ts, 7, 22)) +>undefined : Symbol(undefined) +} + diff --git a/tests/baselines/reference/namespaceImportTypeQuery.types b/tests/baselines/reference/namespaceImportTypeQuery.types index 273a46b1507bc..6023d0961d580 100644 --- a/tests/baselines/reference/namespaceImportTypeQuery.types +++ b/tests/baselines/reference/namespaceImportTypeQuery.types @@ -13,10 +13,10 @@ import * as types from './a'; >types : typeof types let A: typeof types.A; ->A : any ->types.A : any +>A : typeof types.A +>types.A : typeof types.A >types : typeof types ->A : any +>A : typeof types.A let B: typeof types.B; >B : typeof types.B @@ -24,3 +24,21 @@ let B: typeof types.B; >types : typeof types >B : typeof types.B +let t: typeof types = { +>t : typeof types +>types : typeof types +>{ // error: while you can ask for `typeof types.A`, // `typeof types` does not include `A` A: undefined as any, B: undefined as any,} : { A: any; B: any; } + + // error: while you can ask for `typeof types.A`, + // `typeof types` does not include `A` + A: undefined as any, +>A : any +>undefined as any : any +>undefined : undefined + + B: undefined as any, +>B : any +>undefined as any : any +>undefined : undefined +} + diff --git a/tests/baselines/reference/typeofImportTypeOnlyExport.js b/tests/baselines/reference/typeofImportTypeOnlyExport.js new file mode 100644 index 0000000000000..b9cbd6ec6475d --- /dev/null +++ b/tests/baselines/reference/typeofImportTypeOnlyExport.js @@ -0,0 +1,58 @@ +//// [tests/cases/conformance/declarationEmit/typeofImportTypeOnlyExport.ts] //// + +//// [button.ts] +import {classMap} from './lit.js'; +export const c = classMap(); + +//// [lit.ts] +class ClassMapDirective {} + +export type {ClassMapDirective}; + +export const directive = + (class_: C) => + () => ({ + directive: class_, + }); + +export const classMap = directive(ClassMapDirective); + + +//// [lit.js] +"use strict"; +exports.__esModule = true; +exports.classMap = exports.directive = void 0; +var ClassMapDirective = /** @class */ (function () { + function ClassMapDirective() { + } + return ClassMapDirective; +}()); +var directive = function (class_) { + return function () { return ({ + directive: class_ + }); }; +}; +exports.directive = directive; +exports.classMap = (0, exports.directive)(ClassMapDirective); +//// [button.js] +"use strict"; +exports.__esModule = true; +exports.c = void 0; +var lit_js_1 = require("./lit.js"); +exports.c = (0, lit_js_1.classMap)(); + + +//// [lit.d.ts] +declare class ClassMapDirective { +} +export type { ClassMapDirective }; +export declare const directive: (class_: C) => () => { + directive: C; +}; +export declare const classMap: () => { + directive: typeof ClassMapDirective; +}; +//// [button.d.ts] +export declare const c: { + directive: typeof import("./lit.js").ClassMapDirective; +}; diff --git a/tests/baselines/reference/typeofImportTypeOnlyExport.symbols b/tests/baselines/reference/typeofImportTypeOnlyExport.symbols new file mode 100644 index 0000000000000..512c80aa94689 --- /dev/null +++ b/tests/baselines/reference/typeofImportTypeOnlyExport.symbols @@ -0,0 +1,35 @@ +=== tests/cases/conformance/declarationEmit/button.ts === +import {classMap} from './lit.js'; +>classMap : Symbol(classMap, Decl(button.ts, 0, 8)) + +export const c = classMap(); +>c : Symbol(c, Decl(button.ts, 1, 12)) +>classMap : Symbol(classMap, Decl(button.ts, 0, 8)) + +=== tests/cases/conformance/declarationEmit/lit.ts === +class ClassMapDirective {} +>ClassMapDirective : Symbol(ClassMapDirective, Decl(lit.ts, 0, 0)) + +export type {ClassMapDirective}; +>ClassMapDirective : Symbol(ClassMapDirective, Decl(lit.ts, 2, 13)) + +export const directive = +>directive : Symbol(directive, Decl(lit.ts, 4, 12)) + + (class_: C) => +>C : Symbol(C, Decl(lit.ts, 5, 3)) +>class_ : Symbol(class_, Decl(lit.ts, 5, 6)) +>C : Symbol(C, Decl(lit.ts, 5, 3)) + + () => ({ + directive: class_, +>directive : Symbol(directive, Decl(lit.ts, 6, 10)) +>class_ : Symbol(class_, Decl(lit.ts, 5, 6)) + + }); + +export const classMap = directive(ClassMapDirective); +>classMap : Symbol(classMap, Decl(lit.ts, 10, 12)) +>directive : Symbol(directive, Decl(lit.ts, 4, 12)) +>ClassMapDirective : Symbol(ClassMapDirective, Decl(lit.ts, 0, 0)) + diff --git a/tests/baselines/reference/typeofImportTypeOnlyExport.types b/tests/baselines/reference/typeofImportTypeOnlyExport.types new file mode 100644 index 0000000000000..6bc8950868762 --- /dev/null +++ b/tests/baselines/reference/typeofImportTypeOnlyExport.types @@ -0,0 +1,40 @@ +=== tests/cases/conformance/declarationEmit/button.ts === +import {classMap} from './lit.js'; +>classMap : () => { directive: typeof import("tests/cases/conformance/declarationEmit/lit").ClassMapDirective; } + +export const c = classMap(); +>c : { directive: typeof import("tests/cases/conformance/declarationEmit/lit").ClassMapDirective; } +>classMap() : { directive: typeof import("tests/cases/conformance/declarationEmit/lit").ClassMapDirective; } +>classMap : () => { directive: typeof import("tests/cases/conformance/declarationEmit/lit").ClassMapDirective; } + +=== tests/cases/conformance/declarationEmit/lit.ts === +class ClassMapDirective {} +>ClassMapDirective : ClassMapDirective + +export type {ClassMapDirective}; +>ClassMapDirective : ClassMapDirective + +export const directive = +>directive : (class_: C) => () => { directive: C; } + + (class_: C) => +>(class_: C) => () => ({ directive: class_, }) : (class_: C) => () => { directive: C; } +>class_ : C + + () => ({ +>() => ({ directive: class_, }) : () => { directive: C; } +>({ directive: class_, }) : { directive: C; } +>{ directive: class_, } : { directive: C; } + + directive: class_, +>directive : C +>class_ : C + + }); + +export const classMap = directive(ClassMapDirective); +>classMap : () => { directive: typeof ClassMapDirective; } +>directive(ClassMapDirective) : () => { directive: typeof ClassMapDirective; } +>directive : (class_: C) => () => { directive: C; } +>ClassMapDirective : typeof ClassMapDirective + diff --git a/tests/cases/conformance/declarationEmit/typeofImportTypeOnlyExport.ts b/tests/cases/conformance/declarationEmit/typeofImportTypeOnlyExport.ts new file mode 100644 index 0000000000000..aabf57bcc0135 --- /dev/null +++ b/tests/cases/conformance/declarationEmit/typeofImportTypeOnlyExport.ts @@ -0,0 +1,18 @@ +// @declaration: true + +// @Filename: button.ts +import {classMap} from './lit.js'; +export const c = classMap(); + +// @Filename: lit.ts +class ClassMapDirective {} + +export type {ClassMapDirective}; + +export const directive = + (class_: C) => + () => ({ + directive: class_, + }); + +export const classMap = directive(ClassMapDirective); diff --git a/tests/cases/conformance/externalModules/typeOnly/namespaceImportTypeQuery.ts b/tests/cases/conformance/externalModules/typeOnly/namespaceImportTypeQuery.ts index 10e8e020158e8..f82f26607b070 100644 --- a/tests/cases/conformance/externalModules/typeOnly/namespaceImportTypeQuery.ts +++ b/tests/cases/conformance/externalModules/typeOnly/namespaceImportTypeQuery.ts @@ -7,3 +7,10 @@ export class B {}; import * as types from './a'; let A: typeof types.A; let B: typeof types.B; + +let t: typeof types = { + // error: while you can ask for `typeof types.A`, + // `typeof types` does not include `A` + A: undefined as any, + B: undefined as any, +}