Allow type-only imports on ImportEqualsDeclarations (#41573)

* Allow type-only ImportEqualsDeclarations

* Suppress CJS-in-ESM error when type-only

* Add grammar error on import type in import alias

* Update API baselines

* Fix importsNotUsedAsValues with ImportEqualsDeclarations

* Make bad error talk words more good for Daniel. Fixes #41603

* One more error message baseline update

* Update transformer and emitter
This commit is contained in:
Andrew Branch 2020-12-03 13:27:15 -08:00 committed by GitHub
parent 8d952cb43e
commit 69bc3f3b0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 463 additions and 85 deletions

View file

@ -2482,7 +2482,7 @@ namespace ts {
const immediate = resolveExternalModuleName(
node,
getExternalModuleRequireArgument(node) || getExternalModuleImportEqualsDeclarationExpression(node));
const resolved = resolveExternalModuleSymbol(immediate);
const resolved = resolveExternalModuleSymbol(immediate);
markSymbolOfAliasDeclarationIfTypeOnly(node, immediate, resolved, /*overwriteEmpty*/ false);
return resolved;
}
@ -2492,7 +2492,7 @@ namespace ts {
}
function checkAndReportErrorForResolvingImportAliasToTypeOnlySymbol(node: ImportEqualsDeclaration, resolved: Symbol | undefined) {
if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false)) {
if (markSymbolOfAliasDeclarationIfTypeOnly(node, /*immediateTarget*/ undefined, resolved, /*overwriteEmpty*/ false) && !node.isTypeOnly) {
const typeOnlyDeclaration = getTypeOnlyAliasDeclaration(getSymbolOfNode(node))!;
const isExport = typeOnlyDeclarationIsExport(typeOnlyDeclaration);
const message = isExport
@ -6841,6 +6841,7 @@ namespace ts {
addResult(factory.createImportEqualsDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*isTypeOnly*/ false,
uniqueName,
factory.createExternalModuleReference(factory.createStringLiteral(specifier))
), ModifierFlags.None);
@ -6848,6 +6849,7 @@ namespace ts {
addResult(factory.createImportEqualsDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*isTypeOnly*/ false,
factory.createIdentifier(localName),
factory.createQualifiedName(uniqueName, initializer.name as Identifier),
), modifierFlags);
@ -6867,6 +6869,7 @@ namespace ts {
addResult(factory.createImportEqualsDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*isTypeOnly*/ false,
factory.createIdentifier(localName),
isLocalImport
? symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false)
@ -7024,6 +7027,7 @@ namespace ts {
addResult(factory.createImportEqualsDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*isTypeOnly*/ false,
factory.createIdentifier(varName),
symbolToName(target, context, SymbolFlags.All, /*expectsIdentifier*/ false)
), ModifierFlags.None);
@ -36459,9 +36463,12 @@ namespace ts {
checkTypeNameIsReserved(node.name, Diagnostics.Import_name_cannot_be_0);
}
}
if (node.isTypeOnly) {
grammarErrorOnNode(node, Diagnostics.An_import_alias_cannot_use_import_type);
}
}
else {
if (moduleKind >= ModuleKind.ES2015 && !(node.flags & NodeFlags.Ambient)) {
if (moduleKind >= ModuleKind.ES2015 && !node.isTypeOnly && !(node.flags & NodeFlags.Ambient)) {
// Import equals declaration is deprecated in es6 or above
grammarErrorOnNode(node, Diagnostics.Import_assignment_cannot_be_used_when_targeting_ECMAScript_modules_Consider_using_import_Asterisk_as_ns_from_mod_import_a_from_mod_import_d_from_mod_or_another_module_format_instead);
}
@ -36552,19 +36559,30 @@ namespace ts {
});
}
function canConvertImportDeclarationToTypeOnly(statement: Statement) {
return isImportDeclaration(statement) &&
statement.importClause &&
!statement.importClause.isTypeOnly &&
importClauseContainsReferencedImport(statement.importClause) &&
!isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) &&
!importClauseContainsConstEnumUsedAsValue(statement.importClause);
}
function canConvertImportEqualsDeclarationToTypeOnly(statement: Statement) {
return isImportEqualsDeclaration(statement) &&
isExternalModuleReference(statement.moduleReference) &&
!statement.isTypeOnly &&
getSymbolOfNode(statement).isReferenced &&
!isReferencedAliasDeclaration(statement, /*checkChildren*/ false) &&
!getSymbolLinks(getSymbolOfNode(statement)).constEnumReferenced;
}
function checkImportsForTypeOnlyConversion(sourceFile: SourceFile) {
for (const statement of sourceFile.statements) {
if (
isImportDeclaration(statement) &&
statement.importClause &&
!statement.importClause.isTypeOnly &&
importClauseContainsReferencedImport(statement.importClause) &&
!isReferencedAliasDeclaration(statement.importClause, /*checkChildren*/ true) &&
!importClauseContainsConstEnumUsedAsValue(statement.importClause)
) {
if (canConvertImportDeclarationToTypeOnly(statement) || canConvertImportEqualsDeclarationToTypeOnly(statement)) {
error(
statement,
Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_the_importsNotUsedAsValues_is_set_to_error);
Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error);
}
}
}

View file

@ -1112,11 +1112,7 @@
"category": "Message",
"code": 1369
},
"Only ECMAScript imports may use 'import type'.": {
"category": "Error",
"code": 1370
},
"This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.": {
"This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.": {
"category": "Error",
"code": 1371
},
@ -1196,6 +1192,10 @@
"category": "Error",
"code": 1391
},
"An import alias cannot use 'import type'": {
"category": "Error",
"code": 1392
},
"The types of '{0}' are incompatible between these types.": {
"category": "Error",
"code": 2200

View file

@ -3155,6 +3155,10 @@ namespace ts {
emitModifiers(node, node.modifiers);
emitTokenWithComment(SyntaxKind.ImportKeyword, node.modifiers ? node.modifiers.end : node.pos, writeKeyword, node);
writeSpace();
if (node.isTypeOnly) {
emitTokenWithComment(SyntaxKind.TypeKeyword, node.pos, writeKeyword, node);
writeSpace();
}
emit(node.name);
writeSpace();
emitTokenWithComment(SyntaxKind.EqualsToken, node.name.end, writePunctuation, node);

View file

@ -3776,6 +3776,7 @@ namespace ts {
function createImportEqualsDeclaration(
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
isTypeOnly: boolean,
name: string | Identifier,
moduleReference: ModuleReference
) {
@ -3785,6 +3786,7 @@ namespace ts {
modifiers,
name
);
node.isTypeOnly = isTypeOnly;
node.moduleReference = moduleReference;
node.transformFlags |= propagateChildFlags(node.moduleReference);
if (!isExternalModuleReference(node.moduleReference)) node.transformFlags |= TransformFlags.ContainsTypeScript;
@ -3797,14 +3799,16 @@ namespace ts {
node: ImportEqualsDeclaration,
decorators: readonly Decorator[] | undefined,
modifiers: readonly Modifier[] | undefined,
isTypeOnly: boolean,
name: Identifier,
moduleReference: ModuleReference
) {
return node.decorators !== decorators
|| node.modifiers !== modifiers
|| node.isTypeOnly !== isTypeOnly
|| node.name !== name
|| node.moduleReference !== moduleReference
? update(createImportEqualsDeclaration(decorators, modifiers, name, moduleReference), node)
? update(createImportEqualsDeclaration(decorators, modifiers, isTypeOnly, name, moduleReference), node)
: node;
}
@ -5798,7 +5802,7 @@ namespace ts {
isTypeAliasDeclaration(node) ? updateTypeAliasDeclaration(node, node.decorators, modifiers, node.name, node.typeParameters, node.type) :
isEnumDeclaration(node) ? updateEnumDeclaration(node, node.decorators, modifiers, node.name, node.members) :
isModuleDeclaration(node) ? updateModuleDeclaration(node, node.decorators, modifiers, node.name, node.body) :
isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, node.decorators, modifiers, node.name, node.moduleReference) :
isImportEqualsDeclaration(node) ? updateImportEqualsDeclaration(node, node.decorators, modifiers, node.isTypeOnly, node.name, node.moduleReference) :
isImportDeclaration(node) ? updateImportDeclaration(node, node.decorators, modifiers, node.importClause, node.moduleSpecifier) :
isExportAssignment(node) ? updateExportAssignment(node, node.decorators, modifiers, node.expression) :
isExportDeclaration(node) ? updateExportDeclaration(node, node.decorators, modifiers, node.isTypeOnly, node.exportClause, node.moduleSpecifier) :

View file

@ -6929,11 +6929,8 @@ namespace ts {
parseExpected(SyntaxKind.EqualsToken);
const moduleReference = parseModuleReference();
parseSemicolon();
const node = factory.createImportEqualsDeclaration(decorators, modifiers, identifier, moduleReference);
const node = factory.createImportEqualsDeclaration(decorators, modifiers, isTypeOnly, identifier, moduleReference);
const finished = withJSDoc(finishNode(node, pos), hasJSDoc);
if (isTypeOnly) {
parseErrorAtRange(finished, Diagnostics.Only_ECMAScript_imports_may_use_import_type);
}
return finished;
}

View file

@ -681,6 +681,7 @@ namespace ts {
decl,
/*decorators*/ undefined,
decl.modifiers,
decl.isTypeOnly,
decl.name,
factory.updateExternalModuleReference(decl.moduleReference, rewriteModuleSpecifier(decl, specifier))
);

View file

@ -2973,6 +2973,11 @@ namespace ts {
* @param node The import equals declaration node.
*/
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<Statement> {
// Always elide type-only imports
if (node.isTypeOnly) {
return undefined;
}
if (isExternalModuleImportEqualsDeclaration(node)) {
const isReferenced = resolver.isReferencedAliasDeclaration(node);
// If the alias is unreferenced but we want to keep the import, replace with 'import "mod"'.

View file

@ -2925,6 +2925,7 @@ namespace ts {
readonly kind: SyntaxKind.ImportEqualsDeclaration;
readonly parent: SourceFile | ModuleBlock;
readonly name: Identifier;
readonly isTypeOnly: boolean;
// 'EntityName' for an internal module reference, 'ExternalModuleReference' for an external
// module reference.
@ -3037,6 +3038,7 @@ namespace ts {
export type TypeOnlyCompatibleAliasDeclaration =
| ImportClause
| ImportEqualsDeclaration
| NamespaceImport
| ImportOrExportSpecifier
;
@ -7001,8 +7003,8 @@ namespace ts {
updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock;
createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration;
updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration;
createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;

View file

@ -1107,7 +1107,8 @@ namespace ts {
case SyntaxKind.NamespaceImport:
return (node as NamespaceImport).parent.isTypeOnly;
case SyntaxKind.ImportClause:
return (node as ImportClause).isTypeOnly;
case SyntaxKind.ImportEqualsDeclaration:
return (node as ImportClause | ImportEqualsDeclaration).isTypeOnly;
default:
return false;
}

View file

@ -937,6 +937,7 @@ namespace ts {
return factory.updateImportEqualsDeclaration(<ImportEqualsDeclaration>node,
nodesVisitor((<ImportEqualsDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<ImportEqualsDeclaration>node).modifiers, visitor, isModifier),
(<ImportEqualsDeclaration>node).isTypeOnly,
nodeVisitor((<ImportEqualsDeclaration>node).name, visitor, isIdentifier),
nodeVisitor((<ImportEqualsDeclaration>node).moduleReference, visitor, isModuleReference));
@ -949,7 +950,7 @@ namespace ts {
case SyntaxKind.ImportClause:
return factory.updateImportClause(<ImportClause>node,
(node as ImportClause).isTypeOnly,
(<ImportClause>node).isTypeOnly,
nodeVisitor((<ImportClause>node).name, visitor, isIdentifier),
nodeVisitor((<ImportClause>node).namedBindings, visitor, isNamedImportBindings));
@ -980,7 +981,7 @@ namespace ts {
return factory.updateExportDeclaration(<ExportDeclaration>node,
nodesVisitor((<ExportDeclaration>node).decorators, visitor, isDecorator),
nodesVisitor((<ExportDeclaration>node).modifiers, visitor, isModifier),
(node as ExportDeclaration).isTypeOnly,
(<ExportDeclaration>node).isTypeOnly,
nodeVisitor((<ExportDeclaration>node).exportClause, visitor, isNamedExportBindings),
nodeVisitor((<ExportDeclaration>node).moduleSpecifier, visitor, isExpression));

View file

@ -1,6 +1,6 @@
/* @internal */
namespace ts.codefix {
const errorCodes = [Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_the_importsNotUsedAsValues_is_set_to_error.code];
const errorCodes = [Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error.code];
const fixId = "convertToTypeOnlyImport";
registerCodeFix({
errorCodes,

View file

@ -16,6 +16,7 @@ namespace ts.codefix {
variations.push(createAction(context, sourceFile, node, factory.createImportEqualsDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*isTypeOnly*/ false,
namespace.name,
factory.createExternalModuleReference(node.moduleSpecifier)
)));

View file

@ -795,6 +795,7 @@ namespace ts.codefix {
? factory.createImportEqualsDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
typeOnly,
factory.createIdentifier(namespaceLikeImport.name),
factory.createExternalModuleReference(quotedModuleSpecifier))
: factory.createImportDeclaration(

View file

@ -24,7 +24,7 @@ namespace ts.codefix {
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, info: Info) {
const { allowSyntheticDefaults, defaultImportName, namedImports, statement, required } = info;
changes.replaceNode(sourceFile, statement, defaultImportName && !allowSyntheticDefaults
? factory.createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, defaultImportName, factory.createExternalModuleReference(required))
? factory.createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*isTypeOnly*/ false, defaultImportName, factory.createExternalModuleReference(required))
: factory.createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, factory.createImportClause(/*isTypeOnly*/ false, defaultImportName, namedImports), required));
}

View file

@ -245,7 +245,7 @@ namespace ts.refactor {
factory.createImportClause(/*isTypeOnly*/ false, /*name*/ undefined, factory.createNamespaceImport(newNamespaceId)),
newModuleString);
case SyntaxKind.ImportEqualsDeclaration:
return factory.createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, newNamespaceId, factory.createExternalModuleReference(newModuleString));
return factory.createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, /*isTypeOnly*/ false, newNamespaceId, factory.createExternalModuleReference(newModuleString));
case SyntaxKind.VariableDeclaration:
return factory.createVariableDeclaration(newNamespaceId, /*exclamationToken*/ undefined, /*type*/ undefined, createRequireCall(newModuleString));
default:
@ -782,7 +782,7 @@ namespace ts.refactor {
case SyntaxKind.InterfaceDeclaration:
return factory.updateInterfaceDeclaration(d, d.decorators, modifiers, d.name, d.typeParameters, d.heritageClauses, d.members);
case SyntaxKind.ImportEqualsDeclaration:
return factory.updateImportEqualsDeclaration(d, d.decorators, modifiers, d.name, d.moduleReference);
return factory.updateImportEqualsDeclaration(d, d.decorators, modifiers, d.isTypeOnly, d.name, d.moduleReference);
case SyntaxKind.ExpressionStatement:
return Debug.fail(); // Shouldn't try to add 'export' keyword to `exports.x = ...`
default:

View file

@ -1598,6 +1598,7 @@ declare namespace ts {
readonly kind: SyntaxKind.ImportEqualsDeclaration;
readonly parent: SourceFile | ModuleBlock;
readonly name: Identifier;
readonly isTypeOnly: boolean;
readonly moduleReference: ModuleReference;
}
export interface ExternalModuleReference extends Node {
@ -1668,7 +1669,7 @@ declare namespace ts {
readonly name: Identifier;
}
export type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier;
export type TypeOnlyCompatibleAliasDeclaration = ImportClause | NamespaceImport | ImportOrExportSpecifier;
export type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier;
/**
* This is either an `export =` or an `export default` declaration.
* Unless `isExportEquals` is set, this node was parsed as an `export default`.
@ -3410,8 +3411,8 @@ declare namespace ts {
updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock;
createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration;
updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration;
createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
@ -10505,9 +10506,9 @@ declare namespace ts {
/** @deprecated Use `factory.updateNamespaceExportDeclaration` or the factory supplied by your transformation context instead. */
const updateNamespaceExportDeclaration: (node: NamespaceExportDeclaration, name: Identifier) => NamespaceExportDeclaration;
/** @deprecated Use `factory.createImportEqualsDeclaration` or the factory supplied by your transformation context instead. */
const createImportEqualsDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration;
const createImportEqualsDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration;
/** @deprecated Use `factory.updateImportEqualsDeclaration` or the factory supplied by your transformation context instead. */
const updateImportEqualsDeclaration: (node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration;
const updateImportEqualsDeclaration: (node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration;
/** @deprecated Use `factory.createImportDeclaration` or the factory supplied by your transformation context instead. */
const createImportDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression) => ImportDeclaration;
/** @deprecated Use `factory.updateImportDeclaration` or the factory supplied by your transformation context instead. */

View file

@ -1598,6 +1598,7 @@ declare namespace ts {
readonly kind: SyntaxKind.ImportEqualsDeclaration;
readonly parent: SourceFile | ModuleBlock;
readonly name: Identifier;
readonly isTypeOnly: boolean;
readonly moduleReference: ModuleReference;
}
export interface ExternalModuleReference extends Node {
@ -1668,7 +1669,7 @@ declare namespace ts {
readonly name: Identifier;
}
export type ImportOrExportSpecifier = ImportSpecifier | ExportSpecifier;
export type TypeOnlyCompatibleAliasDeclaration = ImportClause | NamespaceImport | ImportOrExportSpecifier;
export type TypeOnlyCompatibleAliasDeclaration = ImportClause | ImportEqualsDeclaration | NamespaceImport | ImportOrExportSpecifier;
/**
* This is either an `export =` or an `export default` declaration.
* Unless `isExportEquals` is set, this node was parsed as an `export default`.
@ -3410,8 +3411,8 @@ declare namespace ts {
updateCaseBlock(node: CaseBlock, clauses: readonly CaseOrDefaultClause[]): CaseBlock;
createNamespaceExportDeclaration(name: string | Identifier): NamespaceExportDeclaration;
updateNamespaceExportDeclaration(node: NamespaceExportDeclaration, name: Identifier): NamespaceExportDeclaration;
createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
createImportEqualsDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
updateImportEqualsDeclaration(node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference): ImportEqualsDeclaration;
createImportDeclaration(decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
updateImportDeclaration(node: ImportDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression): ImportDeclaration;
createImportClause(isTypeOnly: boolean, name: Identifier | undefined, namedBindings: NamedImportBindings | undefined): ImportClause;
@ -6865,9 +6866,9 @@ declare namespace ts {
/** @deprecated Use `factory.updateNamespaceExportDeclaration` or the factory supplied by your transformation context instead. */
const updateNamespaceExportDeclaration: (node: NamespaceExportDeclaration, name: Identifier) => NamespaceExportDeclaration;
/** @deprecated Use `factory.createImportEqualsDeclaration` or the factory supplied by your transformation context instead. */
const createImportEqualsDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: string | Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration;
const createImportEqualsDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: string | Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration;
/** @deprecated Use `factory.updateImportEqualsDeclaration` or the factory supplied by your transformation context instead. */
const updateImportEqualsDeclaration: (node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, name: Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration;
const updateImportEqualsDeclaration: (node: ImportEqualsDeclaration, decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, isTypeOnly: boolean, name: Identifier, moduleReference: ModuleReference) => ImportEqualsDeclaration;
/** @deprecated Use `factory.createImportDeclaration` or the factory supplied by your transformation context instead. */
const createImportDeclaration: (decorators: readonly Decorator[] | undefined, modifiers: readonly Modifier[] | undefined, importClause: ImportClause | undefined, moduleSpecifier: Expression) => ImportDeclaration;
/** @deprecated Use `factory.updateImportDeclaration` or the factory supplied by your transformation context instead. */

View file

@ -0,0 +1,14 @@
//// [tests/cases/conformance/externalModules/typeOnly/cjsImportInES2015.ts] ////
//// [index.d.ts]
declare class SpecialError extends Error {}
export = SpecialError;
//// [index.ts]
import type SpecialError = require("cjs-dep");
function handleError(err: SpecialError) {}
//// [index.js]
function handleError(err) { }
export {};

View file

@ -0,0 +1,17 @@
=== /project/index.ts ===
import type SpecialError = require("cjs-dep");
>SpecialError : Symbol(SpecialError, Decl(index.ts, 0, 0))
function handleError(err: SpecialError) {}
>handleError : Symbol(handleError, Decl(index.ts, 0, 46))
>err : Symbol(err, Decl(index.ts, 1, 21))
>SpecialError : Symbol(SpecialError, Decl(index.ts, 0, 0))
=== /project/node_modules/cjs-dep/index.d.ts ===
declare class SpecialError extends Error {}
>SpecialError : Symbol(SpecialError, Decl(index.d.ts, 0, 0))
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
export = SpecialError;
>SpecialError : Symbol(SpecialError, Decl(index.d.ts, 0, 0))

View file

@ -0,0 +1,16 @@
=== /project/index.ts ===
import type SpecialError = require("cjs-dep");
>SpecialError : typeof SpecialError
function handleError(err: SpecialError) {}
>handleError : (err: SpecialError) => void
>err : SpecialError
=== /project/node_modules/cjs-dep/index.d.ts ===
declare class SpecialError extends Error {}
>SpecialError : SpecialError
>Error : Error
export = SpecialError;
>SpecialError : SpecialError

View file

@ -4,6 +4,7 @@ error TS5056: Cannot write file '/a.js' because it would be overwritten by multi
/a.js(1,1): error TS8006: 'import type' declarations can only be used in TypeScript files.
/a.js(2,1): error TS8006: 'export type' declarations can only be used in TypeScript files.
/b.ts(1,8): error TS1363: A type-only import can specify a default import or named bindings, but not both.
/c.ts(4,1): error TS1392: An import alias cannot use 'import type'
!!! error TS5055: Cannot write file '/a.js' because it would overwrite input file.
@ -26,4 +27,12 @@ error TS5056: Cannot write file '/a.js' because it would be overwritten by multi
export type { A };
~~~~~~~~~~~~~~~~~~
!!! error TS8006: 'export type' declarations can only be used in TypeScript files.
==== /c.ts (1 errors) ====
namespace ns {
export class Foo {}
}
import type Foo = ns.Foo;
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1392: An import alias cannot use 'import type'

View file

@ -12,7 +12,23 @@ import type A, { B, C } from './a';
import type A from './a';
export type { A };
//// [c.ts]
namespace ns {
export class Foo {}
}
import type Foo = ns.Foo;
//// [b.js]
"use strict";
exports.__esModule = true;
//// [c.js]
var ns;
(function (ns) {
var Foo = /** @class */ (function () {
function Foo() {
}
return Foo;
}());
ns.Foo = Foo;
})(ns || (ns = {}));

View file

@ -0,0 +1,23 @@
/c.ts(4,1): error TS1361: 'A' cannot be used as a value because it was imported using 'import type'.
==== /c.ts (1 errors) ====
import type A = require('./a'); // Ok
import type = require('./b'); // Ok
A.prototype; // Error
~
!!! error TS1361: 'A' cannot be used as a value because it was imported using 'import type'.
!!! related TS1376 /c.ts:1:1: 'A' was imported here.
const a: A = { a: 'a' }; // Ok
void type; // Ok
export declare const AConstructor: typeof A; // Ok
==== /a.ts (0 errors) ====
class A { a!: string }
export = A;
==== /b.ts (0 errors) ====
class SomeClass {}
export = SomeClass;

View file

@ -0,0 +1,57 @@
//// [tests/cases/conformance/externalModules/typeOnly/importEqualsDeclaration.ts] ////
//// [a.ts]
class A { a!: string }
export = A;
//// [b.ts]
class SomeClass {}
export = SomeClass;
//// [c.ts]
import type A = require('./a'); // Ok
import type = require('./b'); // Ok
A.prototype; // Error
const a: A = { a: 'a' }; // Ok
void type; // Ok
export declare const AConstructor: typeof A; // Ok
//// [a.js]
"use strict";
var A = /** @class */ (function () {
function A() {
}
return A;
}());
module.exports = A;
//// [b.js]
"use strict";
var SomeClass = /** @class */ (function () {
function SomeClass() {
}
return SomeClass;
}());
module.exports = SomeClass;
//// [c.js]
"use strict";
exports.__esModule = true;
var type = require("./b"); // Ok
A.prototype; // Error
var a = { a: 'a' }; // Ok
void type; // Ok
//// [a.d.ts]
declare class A {
a: string;
}
export = A;
//// [b.d.ts]
declare class SomeClass {
}
export = SomeClass;
//// [c.d.ts]
import type A = require('./a');
export declare const AConstructor: typeof A;

View file

@ -1,17 +0,0 @@
/c.ts(1,1): error TS1370: Only ECMAScript imports may use 'import type'.
==== /c.ts (1 errors) ====
import type T = require('./a'); // Error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1370: Only ECMAScript imports may use 'import type'.
import type = require('./b'); // Ok
==== /a.ts (0 errors) ====
type T = {};
export = T;
==== /b.ts (0 errors) ====
class SomeClass {}
export = SomeClass;

View file

@ -1,7 +1,8 @@
/b.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
/c.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
/b.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
/c.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
/e.ts(1,1): error TS6192: All imports in import declaration are unused.
/g.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
/g.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
/i.ts(1,1): error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
==== /a.ts (0 errors) ====
@ -13,7 +14,7 @@
==== /b.ts (1 errors) ====
import { A, B } from './a'; // Error
~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
let a: A;
let b: B;
console.log(a, b);
@ -21,7 +22,7 @@
==== /c.ts (1 errors) ====
import Default, * as named from './a'; // Error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
let a: Default;
let b: named.B;
console.log(a, b);
@ -48,7 +49,32 @@
==== /g.ts (1 errors) ====
import { C } from './a';
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
let c: C;
let d: C.Two;
console.log(c, d);
console.log(c, d);
==== /h.ts (0 errors) ====
class H {}
export = H;
==== /i.ts (1 errors) ====
import H = require('./h'); // Error
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
let h: H = {};
console.log(h);
==== /j.ts (0 errors) ====
import H = require('./h'); // noUnusedLocals error only
==== /k.ts (0 errors) ====
const enum K { One, Two }
export = K;
==== /l.ts (0 errors) ====
import K = require('./k');
K.One;
==== /j.ts (0 errors) ====
// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207

View file

@ -39,7 +39,30 @@ console.log(c, d);
import { C } from './a';
let c: C;
let d: C.Two;
console.log(c, d);
console.log(c, d);
//// [h.ts]
class H {}
export = H;
//// [i.ts]
import H = require('./h'); // Error
let h: H = {};
console.log(h);
//// [j.ts]
import H = require('./h'); // noUnusedLocals error only
//// [k.ts]
const enum K { One, Two }
export = K;
//// [l.ts]
import K = require('./k');
K.One;
//// [j.ts]
// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207
//// [a.js]
"use strict";
@ -97,3 +120,25 @@ require("./a");
var c;
var d;
console.log(c, d);
//// [h.js]
"use strict";
var H = /** @class */ (function () {
function H() {
}
return H;
}());
module.exports = H;
//// [i.js]
"use strict";
exports.__esModule = true;
var h = {};
console.log(h);
//// [j.js]
// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207
//// [k.js]
"use strict";
exports.__esModule = true;
//// [l.js]
"use strict";
exports.__esModule = true;
0 /* One */;

View file

@ -132,3 +132,48 @@ console.log(c, d);
>c : Symbol(c, Decl(g.ts, 1, 3))
>d : Symbol(d, Decl(g.ts, 2, 3))
=== /h.ts ===
class H {}
>H : Symbol(H, Decl(h.ts, 0, 0))
export = H;
>H : Symbol(H, Decl(h.ts, 0, 0))
=== /i.ts ===
import H = require('./h'); // Error
>H : Symbol(H, Decl(i.ts, 0, 0))
let h: H = {};
>h : Symbol(h, Decl(i.ts, 1, 3))
>H : Symbol(H, Decl(i.ts, 0, 0))
console.log(h);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>h : Symbol(h, Decl(i.ts, 1, 3))
=== /j.ts ===
import H = require('./h'); // noUnusedLocals error only
No type information for this code.
No type information for this code.=== /k.ts ===
const enum K { One, Two }
>K : Symbol(K, Decl(k.ts, 0, 0))
>One : Symbol(K.One, Decl(k.ts, 0, 14))
>Two : Symbol(K.Two, Decl(k.ts, 0, 19))
export = K;
>K : Symbol(K, Decl(k.ts, 0, 0))
=== /l.ts ===
import K = require('./k');
>K : Symbol(K, Decl(l.ts, 0, 0))
K.One;
>K.One : Symbol(K.One, Decl(k.ts, 0, 14))
>K : Symbol(K, Decl(l.ts, 0, 0))
>One : Symbol(K.One, Decl(k.ts, 0, 14))
=== /j.ts ===
// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207
No type information for this code.

View file

@ -128,3 +128,49 @@ console.log(c, d);
>c : C
>d : C.Two
=== /h.ts ===
class H {}
>H : H
export = H;
>H : H
=== /i.ts ===
import H = require('./h'); // Error
>H : typeof H
let h: H = {};
>h : H
>{} : {}
console.log(h);
>console.log(h) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>h : H
=== /j.ts ===
import H = require('./h'); // noUnusedLocals error only
No type information for this code.
No type information for this code.=== /k.ts ===
const enum K { One, Two }
>K : K
>One : K.One
>Two : K.Two
export = K;
>K : K
=== /l.ts ===
import K = require('./k');
>K : typeof K
K.One;
>K.One : K.One
>K : typeof K
>One : K.One
=== /j.ts ===
// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207
No type information for this code.

View file

@ -31,7 +31,7 @@ Output::
>> Screen clear
[12:00:15 AM] Starting compilation in watch mode...
a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
1 import {B} from './b'
  ~~~~~~~~~~~~~~~~~~~~~
@ -110,7 +110,7 @@ Output::
>> Screen clear
[12:00:23 AM] File change detected. Starting incremental compilation...
a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
a.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
1 import {B} from './b'
  ~~~~~~~~~~~~~~~~~~~~~

View file

@ -148,7 +148,7 @@ Output::
>> Screen clear
[12:00:43 AM] File change detected. Starting incremental compilation...
b.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because the 'importsNotUsedAsValues' is set to 'error'.
b.ts:1:1 - error TS1371: This import is never used as a value and must use 'import type' because 'importsNotUsedAsValues' is set to 'error'.
1 import {C} from './a';
  ~~~~~~~~~~~~~~~~~~~~~~

View file

@ -0,0 +1,10 @@
// @module: es2015
// @moduleResolution: node
// @Filename: /project/node_modules/cjs-dep/index.d.ts
declare class SpecialError extends Error {}
export = SpecialError;
// @Filename: /project/index.ts
import type SpecialError = require("cjs-dep");
function handleError(err: SpecialError) {}

View file

@ -13,3 +13,9 @@ import type A, { B, C } from './a';
// @Filename: /a.js
import type A from './a';
export type { A };
// @Filename: /c.ts
namespace ns {
export class Foo {}
}
import type Foo = ns.Foo;

View file

@ -0,0 +1,19 @@
// @noTypesAndSymbols: true
// @declaration: true
// @Filename: /a.ts
class A { a!: string }
export = A;
// @Filename: /b.ts
class SomeClass {}
export = SomeClass;
// @Filename: /c.ts
import type A = require('./a'); // Ok
import type = require('./b'); // Ok
A.prototype; // Error
const a: A = { a: 'a' }; // Ok
void type; // Ok
export declare const AConstructor: typeof A; // Ok

View file

@ -1,14 +0,0 @@
// @noEmit: true
// @noTypesAndSymbols: true
// @Filename: /a.ts
type T = {};
export = T;
// @Filename: /b.ts
class SomeClass {}
export = SomeClass;
// @Filename: /c.ts
import type T = require('./a'); // Error
import type = require('./b'); // Ok

View file

@ -40,4 +40,27 @@ console.log(c, d);
import { C } from './a';
let c: C;
let d: C.Two;
console.log(c, d);
console.log(c, d);
// @Filename: /h.ts
class H {}
export = H;
// @Filename: /i.ts
import H = require('./h'); // Error
let h: H = {};
console.log(h);
// @Filename: /j.ts
import H = require('./h'); // noUnusedLocals error only
// @Filename: /k.ts
const enum K { One, Two }
export = K;
// @Filename: /l.ts
import K = require('./k');
K.One;
// @Filename: /j.ts
// Sad face https://github.com/microsoft/TypeScript/blob/6b04f5039429b9d412696fe2febe39ecc69ad365/src/testRunner/compilerRunner.ts#L207