Skip to content

Account for type-only import specifier in TS 4.5 #43620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JoostK opened this issue Sep 27, 2021 · 1 comment
Closed

Account for type-only import specifier in TS 4.5 #43620

JoostK opened this issue Sep 27, 2021 · 1 comment
Assignees
Labels
area: compiler Issues related to `ngc`, Angular's template compiler refactoring Issue that involves refactoring or code-cleanup state: has PR
Milestone

Comments

@JoostK
Copy link
Member

JoostK commented Sep 27, 2021

For upcoming TS 4.5 our typeToValue logic needs to account for microsoft/TypeScript#45998, where we should report an error if an import specifier is used that has a type-only modifier for a DI token.

export function typeToValue(
typeNode: ts.TypeNode|null, checker: ts.TypeChecker): TypeValueReference {
// It's not possible to get a value expression if the parameter doesn't even have a type.
if (typeNode === null) {
return missingType();
}
if (!ts.isTypeReferenceNode(typeNode)) {
return unsupportedType(typeNode);
}
const symbols = resolveTypeSymbols(typeNode, checker);
if (symbols === null) {
return unknownReference(typeNode);
}
const {local, decl} = symbols;
// It's only valid to convert a type reference to a value reference if the type actually
// has a value declaration associated with it. Note that const enums are an exception,
// because while they do have a value declaration, they don't exist at runtime.
if (decl.valueDeclaration === undefined || decl.flags & ts.SymbolFlags.ConstEnum) {
let typeOnlyDecl: ts.Declaration|null = null;
if (decl.declarations !== undefined && decl.declarations.length > 0) {
typeOnlyDecl = decl.declarations[0];
}
return noValueDeclaration(typeNode, typeOnlyDecl);
}
// The type points to a valid value declaration. Rewrite the TypeReference into an
// Expression which references the value pointed to by the TypeReference, if possible.
// Look at the local `ts.Symbol`'s declarations and see if it comes from an import
// statement. If so, extract the module specifier and the name of the imported type.
const firstDecl = local.declarations && local.declarations[0];
if (firstDecl !== undefined) {
if (ts.isImportClause(firstDecl) && firstDecl.name !== undefined) {
// This is a default import.
// import Foo from 'foo';
if (firstDecl.isTypeOnly) {
// Type-only imports cannot be represented as value.
return typeOnlyImport(typeNode, firstDecl);
}
return {
kind: TypeValueReferenceKind.LOCAL,
expression: firstDecl.name,
defaultImportStatement: firstDecl.parent,
};
} else if (ts.isImportSpecifier(firstDecl)) {
// The symbol was imported by name
// import {Foo} from 'foo';
// or
// import {Foo as Bar} from 'foo';
if (firstDecl.parent.parent.isTypeOnly) {
// Type-only imports cannot be represented as value.
return typeOnlyImport(typeNode, firstDecl.parent.parent);
}
// Determine the name to import (`Foo`) from the import specifier, as the symbol names of
// the imported type could refer to a local alias (like `Bar` in the example above).
const importedName = (firstDecl.propertyName || firstDecl.name).text;
// The first symbol name refers to the local name, which is replaced by `importedName` above.
// Any remaining symbol names make up the complete path to the value.
const [_localName, ...nestedPath] = symbols.symbolNames;
const moduleName = extractModuleName(firstDecl.parent.parent.parent);
return {
kind: TypeValueReferenceKind.IMPORTED,
valueDeclaration: decl.valueDeclaration,
moduleName,
importedName,
nestedPath
};
} else if (ts.isNamespaceImport(firstDecl)) {
// The import is a namespace import
// import * as Foo from 'foo';
if (firstDecl.parent.isTypeOnly) {
// Type-only imports cannot be represented as value.
return typeOnlyImport(typeNode, firstDecl.parent);
}
if (symbols.symbolNames.length === 1) {
// The type refers to the namespace itself, which cannot be represented as a value.
return namespaceImport(typeNode, firstDecl.parent);
}
// The first symbol name refers to the local name of the namespace, which is is discarded
// as a new namespace import will be generated. This is followed by the symbol name that needs
// to be imported and any remaining names that constitute the complete path to the value.
const [_ns, importedName, ...nestedPath] = symbols.symbolNames;
const moduleName = extractModuleName(firstDecl.parent.parent);
return {
kind: TypeValueReferenceKind.IMPORTED,
valueDeclaration: decl.valueDeclaration,
moduleName,
importedName,
nestedPath
};
}
}
// If the type is not imported, the type reference can be converted into an expression as is.
const expression = typeNodeToValueExpr(typeNode);
if (expression !== null) {
return {
kind: TypeValueReferenceKind.LOCAL,
expression,
defaultImportStatement: null,
};
} else {
return unsupportedType(typeNode);
}
}

For example the following should be invalid:

import { type MyService } from './service.ts';

@Injectable()
export class OtherService {
  constructor(private service: MyService) {}
}

The compiler is already capable of reporting errors for type-only import statements, it just needs to be expanded for type-only import specifiers.

@JoostK JoostK added refactoring Issue that involves refactoring or code-cleanup area: compiler Issues related to `ngc`, Angular's template compiler labels Sep 27, 2021
@ngbot ngbot bot modified the milestone: needsTriage Sep 27, 2021
@crisbeto crisbeto self-assigned this Nov 15, 2021
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 15, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 17, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 20, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 23, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 24, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 30, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 30, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.
crisbeto added a commit to crisbeto/angular that referenced this issue Nov 30, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.
dimakuba pushed a commit to dimakuba/angular that referenced this issue Dec 28, 2021
Adds support for TypeScript 4.5. Includes the following changes:
* Bumping the package versions.
* Fixing a few calls to `createExportSpecifier` and `createImportSpecifier` that require an extra parameter.
* Adding some missing methods to the TS compiler hosts.
* Fixing an issue in the TS mocks for the ngcc tests where a regex was too agressive and was trying to match a path like `/node_modules/@typescript/lib-es5`.
* Accounting for type-only import specifiers when reporting DI errors (see angular#43620).

Fixes angular#43620.

PR Close angular#44164
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Dec 31, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: compiler Issues related to `ngc`, Angular's template compiler refactoring Issue that involves refactoring or code-cleanup state: has PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants