mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 17:05:58 -05:00
Allow referencing type-only exports as namespace members in ImportTypes and TypeQueries (#49056)
* Allow referencing type-only exports as namespace members in ImportTypes and TypeQueries * Add extra test case * ;; -> ; * undefined -> false Co-authored-by: Daniel Rosenwasser <DanielRosenwasser@users.noreply.github.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
58
tests/baselines/reference/typeofImportTypeOnlyExport.js
Normal file
58
tests/baselines/reference/typeofImportTypeOnlyExport.js
Normal file
@@ -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 =
|
||||
<C>(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: <C>(class_: C) => () => {
|
||||
directive: C;
|
||||
};
|
||||
export declare const classMap: () => {
|
||||
directive: typeof ClassMapDirective;
|
||||
};
|
||||
//// [button.d.ts]
|
||||
export declare const c: {
|
||||
directive: typeof import("./lit.js").ClassMapDirective;
|
||||
};
|
||||
35
tests/baselines/reference/typeofImportTypeOnlyExport.symbols
Normal file
35
tests/baselines/reference/typeofImportTypeOnlyExport.symbols
Normal file
@@ -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))
|
||||
|
||||
<C>(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))
|
||||
|
||||
40
tests/baselines/reference/typeofImportTypeOnlyExport.types
Normal file
40
tests/baselines/reference/typeofImportTypeOnlyExport.types
Normal file
@@ -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 : <C>(class_: C) => () => { directive: C; }
|
||||
|
||||
<C>(class_: C) =>
|
||||
><C>(class_: C) => () => ({ directive: class_, }) : <C>(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 : <C>(class_: C) => () => { directive: C; }
|
||||
>ClassMapDirective : typeof ClassMapDirective
|
||||
|
||||
@@ -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 =
|
||||
<C>(class_: C) =>
|
||||
() => ({
|
||||
directive: class_,
|
||||
});
|
||||
|
||||
export const classMap = directive(ClassMapDirective);
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user