fix(tsc-wrapped): ignore `|null` and `|undefined` when collecting types (#16222)

This commit is contained in:
Chuck Jazdzewski 2017-04-20 17:34:44 -07:00
parent 27761b4500
commit 1651a8f189
3 changed files with 54 additions and 1 deletions

View File

@ -191,7 +191,6 @@ export class StaticReflector implements CompileReflector {
if (paramType) nestedResult.push(paramType); if (paramType) nestedResult.push(paramType);
const decorators = parameterDecorators ? parameterDecorators[index] : null; const decorators = parameterDecorators ? parameterDecorators[index] : null;
if (decorators) { if (decorators) {
if (paramType) nestedResult.push(paramType);
nestedResult.push(...decorators); nestedResult.push(...decorators);
} }
parameters !.push(nestedResult); parameters !.push(nestedResult);

View File

@ -442,6 +442,36 @@ export class Evaluator {
(<MetadataImportedSymbolReferenceExpression>typeReference).arguments = args; (<MetadataImportedSymbolReferenceExpression>typeReference).arguments = args;
} }
return recordEntry(typeReference, node); return recordEntry(typeReference, node);
case ts.SyntaxKind.UnionType:
const unionType = <ts.UnionTypeNode>node;
// Remove null and undefined from the list of unions.
const references = unionType.types
.filter(
n => n.kind != ts.SyntaxKind.NullKeyword &&
n.kind != ts.SyntaxKind.UndefinedKeyword)
.map(n => this.evaluateNode(n));
// The remmaining reference must be the same. If two have type arguments consider them
// different even if the type arguments are the same.
let candidate: any = null;
for (let i = 0; i < references.length; i++) {
const reference = references[i];
if (isMetadataSymbolicReferenceExpression(reference)) {
if (candidate) {
if ((reference as any).name == candidate.name &&
(reference as any).module == candidate.module && !(reference as any).arguments) {
candidate = reference;
}
} else {
candidate = reference;
}
} else {
return reference;
}
}
if (candidate) return candidate;
break;
case ts.SyntaxKind.NoSubstitutionTemplateLiteral: case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
case ts.SyntaxKind.StringLiteral: case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.TemplateHead: case ts.SyntaxKind.TemplateHead:

View File

@ -707,6 +707,30 @@ describe('Collector', () => {
}); });
}); });
it('should ignore |null or |undefined in type expressions', () => {
const source = ts.createSourceFile(
'somefile.ts', `
import {Foo} from './foo';
export class SomeClass {
constructor (a: Foo, b: Foo | null, c: Foo | undefined, d: Foo | undefined | null, e: Foo | undefined | null | Foo) {}
}
`,
ts.ScriptTarget.Latest, true);
const metadata = collector.getMetadata(source);
expect((metadata.metadata['SomeClass'] as ClassMetadata).members).toEqual({
__ctor__: [{
__symbolic: 'constructor',
parameters: [
{__symbolic: 'reference', module: './foo', name: 'Foo'},
{__symbolic: 'reference', module: './foo', name: 'Foo'},
{__symbolic: 'reference', module: './foo', name: 'Foo'},
{__symbolic: 'reference', module: './foo', name: 'Foo'},
{__symbolic: 'reference', module: './foo', name: 'Foo'}
]
}]
});
});
describe('in strict mode', () => { describe('in strict mode', () => {
it('should throw if an error symbol is collecting a reference to a non-exported symbol', () => { it('should throw if an error symbol is collecting a reference to a non-exported symbol', () => {
const source = program.getSourceFile('/local-symbol-ref.ts'); const source = program.getSourceFile('/local-symbol-ref.ts');