mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Support export type * (#52217)
This commit is contained in:
+60
-20
@@ -3443,7 +3443,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (result && errorLocation && meaning & SymbolFlags.Value && result.flags & SymbolFlags.Alias && !(result.flags & SymbolFlags.Value) && !isValidTypeOnlyAliasUseSite(errorLocation)) {
|
||||
const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(result, SymbolFlags.Value);
|
||||
if (typeOnlyDeclaration) {
|
||||
const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier
|
||||
const message = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport
|
||||
? Diagnostics._0_cannot_be_used_as_a_value_because_it_was_exported_using_export_type
|
||||
: Diagnostics._0_cannot_be_used_as_a_value_because_it_was_imported_using_import_type;
|
||||
const unescapedName = unescapeLeadingUnderscores(name);
|
||||
@@ -3464,7 +3464,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
diagnostic,
|
||||
createDiagnosticForNode(
|
||||
typeOnlyDeclaration,
|
||||
typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier ? Diagnostics._0_was_exported_here : Diagnostics._0_was_imported_here,
|
||||
typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration || typeOnlyDeclaration.kind === SyntaxKind.NamespaceExport
|
||||
? Diagnostics._0_was_exported_here
|
||||
: Diagnostics._0_was_imported_here,
|
||||
unescapedName));
|
||||
}
|
||||
|
||||
@@ -3861,7 +3863,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) {
|
||||
if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false) && !node.isTypeOnly) {
|
||||
const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfDeclaration(node))!;
|
||||
const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier;
|
||||
const isExport = typeOnlyDeclaration.kind === SyntaxKind.ExportSpecifier || typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration;
|
||||
const message = isExport
|
||||
? Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_exported_using_export_type
|
||||
: Diagnostics.An_import_alias_cannot_reference_a_declaration_that_was_imported_using_import_type;
|
||||
@@ -3869,7 +3871,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
? Diagnostics._0_was_exported_here
|
||||
: Diagnostics._0_was_imported_here;
|
||||
|
||||
const name = unescapeLeadingUnderscores(typeOnlyDeclaration.name.escapedText);
|
||||
// TODO: how to get name for export *?
|
||||
const name = typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration ? "*" : unescapeLeadingUnderscores(typeOnlyDeclaration.name.escapedText);
|
||||
addRelatedInfo(error(node.moduleReference, message), createDiagnosticForNode(typeOnlyDeclaration, relatedMessage, name));
|
||||
}
|
||||
}
|
||||
@@ -4083,7 +4086,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (symbol.flags & SymbolFlags.Module) {
|
||||
const exportSymbol = getExportsOfSymbol(symbol).get(name.escapedText);
|
||||
const resolved = resolveSymbol(exportSymbol, dontResolveAlias);
|
||||
markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false);
|
||||
const exportStarDeclaration = getSymbolLinks(symbol).typeOnlyExportStarMap?.get(name.escapedText);
|
||||
markSymbolOfAliasDeclarationIfTypeOnly(specifier, exportSymbol, resolved, /*overwriteEmpty*/ false, exportStarDeclaration, name.escapedText);
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
@@ -4444,6 +4448,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
immediateTarget: Symbol | undefined,
|
||||
finalTarget: Symbol | undefined,
|
||||
overwriteEmpty: boolean,
|
||||
exportStarDeclaration?: ExportDeclaration & { readonly isTypeOnly: true },
|
||||
exportStarName?: __String,
|
||||
): boolean {
|
||||
if (!aliasDeclaration || isPropertyAccessExpression(aliasDeclaration)) return false;
|
||||
|
||||
@@ -4455,6 +4461,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
links.typeOnlyDeclaration = aliasDeclaration;
|
||||
return true;
|
||||
}
|
||||
if (exportStarDeclaration) {
|
||||
const links = getSymbolLinks(sourceSymbol);
|
||||
links.typeOnlyDeclaration = exportStarDeclaration;
|
||||
if (sourceSymbol.escapedName !== exportStarName) {
|
||||
links.typeOnlyExportStarName = exportStarName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const links = getSymbolLinks(sourceSymbol);
|
||||
return markSymbolOfAliasDeclarationIfTypeOnlyWorker(links, immediateTarget, overwriteEmpty)
|
||||
@@ -4480,7 +4494,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return links.typeOnlyDeclaration || undefined;
|
||||
}
|
||||
if (links.typeOnlyDeclaration) {
|
||||
return getAllSymbolFlags(resolveAlias(links.typeOnlyDeclaration.symbol)) & include ? links.typeOnlyDeclaration : undefined;
|
||||
const resolved = links.typeOnlyDeclaration.kind === SyntaxKind.ExportDeclaration
|
||||
? resolveSymbol(getExportsOfModule(links.typeOnlyDeclaration.symbol.parent!).get(links.typeOnlyExportStarName || symbol.escapedName))!
|
||||
: resolveAlias(links.typeOnlyDeclaration.symbol);
|
||||
return getAllSymbolFlags(resolved) & include ? links.typeOnlyDeclaration : undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -5203,7 +5220,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
function getExportsOfModule(moduleSymbol: Symbol): SymbolTable {
|
||||
const links = getSymbolLinks(moduleSymbol);
|
||||
return links.resolvedExports || (links.resolvedExports = getExportsOfModuleWorker(moduleSymbol));
|
||||
if (!links.resolvedExports) {
|
||||
const { exports, typeOnlyExportStarMap } = getExportsOfModuleWorker(moduleSymbol);
|
||||
links.resolvedExports = exports;
|
||||
links.typeOnlyExportStarMap = typeOnlyExportStarMap;
|
||||
}
|
||||
return links.resolvedExports;
|
||||
}
|
||||
|
||||
interface ExportCollisionTracker {
|
||||
@@ -5243,21 +5265,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
});
|
||||
}
|
||||
|
||||
function getExportsOfModuleWorker(moduleSymbol: Symbol): SymbolTable {
|
||||
function getExportsOfModuleWorker(moduleSymbol: Symbol) {
|
||||
const visitedSymbols: Symbol[] = [];
|
||||
let typeOnlyExportStarMap: UnderscoreEscapedMap<ExportDeclaration & { readonly isTypeOnly: true }> | undefined;
|
||||
const nonTypeOnlyNames = new Set<__String>();
|
||||
|
||||
// A module defined by an 'export=' consists of one export that needs to be resolved
|
||||
moduleSymbol = resolveExternalModuleSymbol(moduleSymbol);
|
||||
const exports = visit(moduleSymbol) || emptySymbols;
|
||||
|
||||
return visit(moduleSymbol) || emptySymbols;
|
||||
if (typeOnlyExportStarMap) {
|
||||
nonTypeOnlyNames.forEach(name => typeOnlyExportStarMap!.delete(name));
|
||||
}
|
||||
|
||||
return {
|
||||
exports,
|
||||
typeOnlyExportStarMap,
|
||||
};
|
||||
|
||||
// The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example,
|
||||
// module 'a' can 'export * from "b"' and 'b' can 'export * from "a"' without error.
|
||||
function visit(symbol: Symbol | undefined): SymbolTable | undefined {
|
||||
function visit(symbol: Symbol | undefined, exportStar?: ExportDeclaration, isTypeOnly?: boolean): SymbolTable | undefined {
|
||||
if (!isTypeOnly && symbol?.exports) {
|
||||
// Add non-type-only names before checking if we've visited this module,
|
||||
// because we might have visited it via an 'export type *', and visiting
|
||||
// again with 'export *' will override the type-onlyness of its exports.
|
||||
symbol.exports.forEach((_, name) => nonTypeOnlyNames.add(name));
|
||||
}
|
||||
if (!(symbol && symbol.exports && pushIfUnique(visitedSymbols, symbol))) {
|
||||
return;
|
||||
}
|
||||
const symbols = new Map(symbol.exports);
|
||||
|
||||
// All export * declarations are collected in an __export symbol by the binder
|
||||
const exportStars = symbol.exports.get(InternalSymbolName.ExportStar);
|
||||
if (exportStars) {
|
||||
@@ -5266,7 +5305,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (exportStars.declarations) {
|
||||
for (const node of exportStars.declarations) {
|
||||
const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!);
|
||||
const exportedSymbols = visit(resolvedModule);
|
||||
const exportedSymbols = visit(resolvedModule, node as ExportDeclaration, isTypeOnly || (node as ExportDeclaration).isTypeOnly);
|
||||
extendExportSymbols(
|
||||
nestedSymbols,
|
||||
exportedSymbols,
|
||||
@@ -5291,6 +5330,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
});
|
||||
extendExportSymbols(symbols, nestedSymbols);
|
||||
}
|
||||
if (exportStar?.isTypeOnly) {
|
||||
typeOnlyExportStarMap ??= new Map();
|
||||
symbols.forEach((_, escapedName) => typeOnlyExportStarMap!.set(
|
||||
escapedName,
|
||||
exportStar as ExportDeclaration & { readonly isTypeOnly: true }));
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
}
|
||||
@@ -8597,7 +8642,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
for (const node of symbol.declarations) {
|
||||
const resolvedModule = resolveExternalModuleName(node, (node as ExportDeclaration).moduleSpecifier!);
|
||||
if (!resolvedModule) continue;
|
||||
addResult(factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ false, /*exportClause*/ undefined, factory.createStringLiteral(getSpecifierForModuleSymbol(resolvedModule, context))), ModifierFlags.None);
|
||||
addResult(factory.createExportDeclaration(/*modifiers*/ undefined, /*isTypeOnly*/ (node as ExportDeclaration).isTypeOnly, /*exportClause*/ undefined, factory.createStringLiteral(getSpecifierForModuleSymbol(resolvedModule, context))), ModifierFlags.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12219,7 +12264,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (!links[resolutionKind]) {
|
||||
const isStatic = resolutionKind === MembersOrExportsResolutionKind.resolvedExports;
|
||||
const earlySymbols = !isStatic ? symbol.members :
|
||||
symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol) :
|
||||
symbol.flags & SymbolFlags.Module ? getExportsOfModuleWorker(symbol).exports :
|
||||
symbol.exports;
|
||||
|
||||
// In the event we recursively resolve the members/exports of the symbol, we
|
||||
@@ -43738,13 +43783,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
|
||||
function checkGrammarExportDeclaration(node: ExportDeclaration): boolean {
|
||||
if (node.isTypeOnly) {
|
||||
if (node.exportClause?.kind === SyntaxKind.NamedExports) {
|
||||
return checkGrammarNamedImportsOrExports(node.exportClause);
|
||||
}
|
||||
else {
|
||||
return grammarErrorOnNode(node, Diagnostics.Only_named_exports_may_use_export_type);
|
||||
}
|
||||
if (node.isTypeOnly && node.exportClause?.kind === SyntaxKind.NamedExports) {
|
||||
return checkGrammarNamedImportsOrExports(node.exportClause);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1232,10 +1232,6 @@
|
||||
"category": "Error",
|
||||
"code": 1382
|
||||
},
|
||||
"Only named exports may use 'export type'.": {
|
||||
"category": "Error",
|
||||
"code": 1383
|
||||
},
|
||||
"Function type notation must be parenthesized when used in a union type.": {
|
||||
"category": "Error",
|
||||
"code": 1385
|
||||
|
||||
+13
-2
@@ -3788,16 +3788,25 @@ export type TypeOnlyCompatibleAliasDeclaration =
|
||||
| ImportEqualsDeclaration
|
||||
| NamespaceImport
|
||||
| ImportOrExportSpecifier
|
||||
| ExportDeclaration
|
||||
| NamespaceExport
|
||||
;
|
||||
|
||||
export type TypeOnlyAliasDeclaration =
|
||||
export type TypeOnlyImportDeclaration =
|
||||
| ImportClause & { readonly isTypeOnly: true, readonly name: Identifier }
|
||||
| ImportEqualsDeclaration & { readonly isTypeOnly: true }
|
||||
| NamespaceImport & { readonly parent: ImportClause & { readonly isTypeOnly: true } }
|
||||
| ImportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedImports & { readonly parent: ImportClause & { readonly isTypeOnly: true } } })
|
||||
| ExportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } })
|
||||
;
|
||||
|
||||
export type TypeOnlyExportDeclaration =
|
||||
| ExportSpecifier & ({ readonly isTypeOnly: true } | { readonly parent: NamedExports & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } })
|
||||
| ExportDeclaration & { readonly isTypeOnly: true } // export * from "mod"
|
||||
| NamespaceExport & { readonly parent: ExportDeclaration & { readonly isTypeOnly: true } } // export * as ns from "mod"
|
||||
;
|
||||
|
||||
export type TypeOnlyAliasDeclaration = TypeOnlyImportDeclaration | TypeOnlyExportDeclaration;
|
||||
|
||||
/**
|
||||
* This is either an `export =` or an `export default` declaration.
|
||||
* Unless `isExportEquals` is set, this node was parsed as an `export default`.
|
||||
@@ -5792,6 +5801,8 @@ export interface SymbolLinks {
|
||||
deferralParent?: Type; // Source union/intersection of a deferred type
|
||||
cjsExportMerged?: Symbol; // Version of the symbol with all non export= exports merged with the export= target
|
||||
typeOnlyDeclaration?: TypeOnlyAliasDeclaration | false; // First resolved alias declaration that makes the symbol only usable in type constructs
|
||||
typeOnlyExportStarMap?: UnderscoreEscapedMap<ExportDeclaration & { readonly isTypeOnly: true }>; // Set on a module symbol when some of its exports were resolved through a 'export type * from "mod"' declaration
|
||||
typeOnlyExportStarName?: __String; // Set to the name of the symbol re-exported by an 'export type *' declaration, when different from the symbol name
|
||||
isConstructorDeclaredProperty?: boolean; // Property declared through 'this.x = ...' assignment in constructor
|
||||
tupleLabelDeclaration?: NamedTupleMember | ParameterDeclaration; // Declaration associated with the tuple's label
|
||||
accessibleChainCache?: Map<string, Symbol[] | undefined>;
|
||||
|
||||
@@ -55,6 +55,7 @@ import {
|
||||
EnumDeclaration,
|
||||
every,
|
||||
ExportAssignment,
|
||||
ExportDeclaration,
|
||||
ExportSpecifier,
|
||||
Expression,
|
||||
FileReference,
|
||||
@@ -92,7 +93,6 @@ import {
|
||||
Identifier,
|
||||
ImportClause,
|
||||
ImportEqualsDeclaration,
|
||||
ImportOrExportSpecifier,
|
||||
ImportSpecifier,
|
||||
ImportTypeNode,
|
||||
isAccessExpression,
|
||||
@@ -214,6 +214,7 @@ import {
|
||||
NamedExportBindings,
|
||||
NamedImportBindings,
|
||||
NamespaceBody,
|
||||
NamespaceExport,
|
||||
NamespaceImport,
|
||||
NewExpression,
|
||||
Node,
|
||||
@@ -270,6 +271,8 @@ import {
|
||||
TypeElement,
|
||||
TypeNode,
|
||||
TypeOnlyAliasDeclaration,
|
||||
TypeOnlyExportDeclaration,
|
||||
TypeOnlyImportDeclaration,
|
||||
TypeParameterDeclaration,
|
||||
TypeReferenceType,
|
||||
UnaryExpression,
|
||||
@@ -1480,19 +1483,33 @@ export function isImportOrExportSpecifier(node: Node): node is ImportSpecifier |
|
||||
return isImportSpecifier(node) || isExportSpecifier(node);
|
||||
}
|
||||
|
||||
export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration {
|
||||
export function isTypeOnlyImportDeclaration(node: Node): node is TypeOnlyImportDeclaration {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ImportSpecifier:
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
return (node as ImportOrExportSpecifier).isTypeOnly || (node as ImportOrExportSpecifier).parent.parent.isTypeOnly;
|
||||
return (node as ImportSpecifier).isTypeOnly || (node as ImportSpecifier).parent.parent.isTypeOnly;
|
||||
case SyntaxKind.NamespaceImport:
|
||||
return (node as NamespaceImport).parent.isTypeOnly;
|
||||
case SyntaxKind.ImportClause:
|
||||
case SyntaxKind.ImportEqualsDeclaration:
|
||||
return (node as ImportClause | ImportEqualsDeclaration).isTypeOnly;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isTypeOnlyExportDeclaration(node: Node): node is TypeOnlyExportDeclaration {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ExportSpecifier:
|
||||
return (node as ExportSpecifier).isTypeOnly || (node as ExportSpecifier).parent.parent.isTypeOnly;
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
return (node as ExportDeclaration).isTypeOnly && !!(node as ExportDeclaration).moduleSpecifier && !(node as ExportDeclaration).exportClause;
|
||||
case SyntaxKind.NamespaceExport:
|
||||
return (node as NamespaceExport).parent.isTypeOnly;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isTypeOnlyImportOrExportDeclaration(node: Node): node is TypeOnlyAliasDeclaration {
|
||||
return isTypeOnlyImportDeclaration(node) || isTypeOnlyExportDeclaration(node);
|
||||
}
|
||||
|
||||
export function isAssertionKey(node: Node): node is AssertionKey {
|
||||
|
||||
@@ -227,6 +227,7 @@ import {
|
||||
isTypeLiteralNode,
|
||||
isTypeNode,
|
||||
isTypeOfExpression,
|
||||
isTypeOnlyImportDeclaration,
|
||||
isTypeOnlyImportOrExportDeclaration,
|
||||
isTypeReferenceType,
|
||||
isValidTypeOnlyAliasUseSite,
|
||||
@@ -352,7 +353,7 @@ import {
|
||||
typeHasCallOrConstructSignatures,
|
||||
TypeLiteralNode,
|
||||
TypeNode,
|
||||
TypeOnlyAliasDeclaration,
|
||||
TypeOnlyImportDeclaration,
|
||||
TypeQueryNode,
|
||||
TypeReferenceNode,
|
||||
unescapeLeadingUnderscores,
|
||||
@@ -467,8 +468,8 @@ interface SymbolOriginInfoResolvedExport extends SymbolOriginInfo {
|
||||
moduleSpecifier: string;
|
||||
}
|
||||
|
||||
interface SymbolOriginInfoTypeOnlyAlias extends SymbolOriginInfo {
|
||||
declaration: TypeOnlyAliasDeclaration;
|
||||
interface SymbolOriginInfoTypeOnlyImport extends SymbolOriginInfo {
|
||||
declaration: TypeOnlyImportDeclaration;
|
||||
}
|
||||
|
||||
interface SymbolOriginInfoObjectLiteralMethod extends SymbolOriginInfo {
|
||||
@@ -509,7 +510,7 @@ function originIsNullableMember(origin: SymbolOriginInfo): boolean {
|
||||
return !!(origin.kind & SymbolOriginInfoKind.Nullable);
|
||||
}
|
||||
|
||||
function originIsTypeOnlyAlias(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoTypeOnlyAlias {
|
||||
function originIsTypeOnlyAlias(origin: SymbolOriginInfo | undefined): origin is SymbolOriginInfoTypeOnlyImport {
|
||||
return !!(origin && origin.kind & SymbolOriginInfoKind.TypeOnlyAlias);
|
||||
}
|
||||
|
||||
@@ -3351,9 +3352,9 @@ function getCompletionData(
|
||||
symbolToSortTextMap[getSymbolId(symbol)] = SortText.GlobalsOrKeywords;
|
||||
}
|
||||
if (typeOnlyAliasNeedsPromotion && !(symbol.flags & SymbolFlags.Value)) {
|
||||
const typeOnlyAliasDeclaration = symbol.declarations && find(symbol.declarations, isTypeOnlyImportOrExportDeclaration);
|
||||
const typeOnlyAliasDeclaration = symbol.declarations && find(symbol.declarations, isTypeOnlyImportDeclaration);
|
||||
if (typeOnlyAliasDeclaration) {
|
||||
const origin: SymbolOriginInfoTypeOnlyAlias = { kind: SymbolOriginInfoKind.TypeOnlyAlias, declaration: typeOnlyAliasDeclaration };
|
||||
const origin: SymbolOriginInfoTypeOnlyImport = { kind: SymbolOriginInfoKind.TypeOnlyAlias, declaration: typeOnlyAliasDeclaration };
|
||||
symbolToOriginInfoMap[i] = origin;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user