fix(core): undecorated-classes-with-decorated-fields migration should avoid error if base class has no value declaration (#36543)
The undecorated-classes-with-decorated-fields migration relies on the type checker to resolve base classes of individual classes. It could happen that resolved base classes have no value declaration. e.g. if they are declared through an interface in the default types. Currently the migration will throw in such situations because it assumes that `ts.Symbol#valueDeclaration` is always present. This is not the case, but we don't get good type-checking here due to a bug in the TypeScript types. See: https://github.com/microsoft/TypeScript/issues/24706. Fixes #36522. PR Close #36543
This commit is contained in:
parent
6ab43d7335
commit
ca677481a2
|
@ -74,7 +74,8 @@ describe('Undecorated classes with decorated fields migration', () => {
|
|||
.toContain(`import { Directive, Input } from '@angular/core';`);
|
||||
});
|
||||
|
||||
it('should not generate conflicting imports there is a different `Directive` symbol', async() => {
|
||||
it('should not generate conflicting imports there is a different `Directive` symbol',
|
||||
async () => {
|
||||
writeFile('/index.ts', `
|
||||
import { HostBinding } from '@angular/core';
|
||||
|
||||
|
@ -292,6 +293,27 @@ describe('Undecorated classes with decorated fields migration', () => {
|
|||
expect(fileContent).toMatch(/}\s+export class MyCompWrapped/);
|
||||
});
|
||||
|
||||
it('should not throw if undecorated class extends from unresolved declaration', async () => {
|
||||
writeFile('/lib.d.ts', `
|
||||
// Fakes the ES5 error default lib types. Since we are in a virtual tree,
|
||||
// the default lib types from TypeScript are not available.
|
||||
interface ErrorConstructor {}
|
||||
declare var Error: ErrorConstructor;
|
||||
`);
|
||||
writeFile('/index.ts', `
|
||||
export class MyCustomErrorClass extends Error {}
|
||||
`);
|
||||
|
||||
let error: any = null;
|
||||
try {
|
||||
await runMigration();
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
expect(error).toBe(null);
|
||||
});
|
||||
|
||||
function writeFile(filePath: string, contents: string) {
|
||||
host.sync.write(normalize(filePath), virtualFs.stringToFileBuffer(contents));
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ export function findBaseClassDeclarations(node: ts.ClassDeclaration, typeChecker
|
|||
break;
|
||||
}
|
||||
const symbol = typeChecker.getTypeAtLocation(baseTypes[0]).getSymbol();
|
||||
if (!symbol || !ts.isClassDeclaration(symbol.valueDeclaration)) {
|
||||
// Note: `ts.Symbol#valueDeclaration` can be undefined. TypeScript has an incorrect type
|
||||
// for this: https://github.com/microsoft/TypeScript/issues/24706.
|
||||
if (!symbol || !symbol.valueDeclaration || !ts.isClassDeclaration(symbol.valueDeclaration)) {
|
||||
break;
|
||||
}
|
||||
result.push({identifier: baseTypes[0], node: symbol.valueDeclaration});
|
||||
|
|
Loading…
Reference in New Issue