diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_parameter_emitter.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_parameter_emitter.ts index c973742cea..018b36a3f8 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_parameter_emitter.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_parameter_emitter.ts @@ -32,14 +32,18 @@ export class TypeParameterEmitter { } return this.typeParameters.every(typeParam => { - if (typeParam.constraint === undefined) { - return true; - } - - return canEmitType(typeParam.constraint, type => this.resolveTypeReference(type)); + return this.canEmitType(typeParam.constraint) && this.canEmitType(typeParam.default); }); } + private canEmitType(type: ts.TypeNode|undefined): boolean { + if (type === undefined) { + return true; + } + + return canEmitType(type, typeReference => this.resolveTypeReference(typeReference)); + } + /** * Emits the type parameters using the provided emitter function for `Reference`s. */ @@ -53,12 +57,14 @@ export class TypeParameterEmitter { return this.typeParameters.map(typeParam => { const constraint = typeParam.constraint !== undefined ? emitter.emitType(typeParam.constraint) : undefined; + const defaultType = + typeParam.default !== undefined ? emitter.emitType(typeParam.default) : undefined; return ts.updateTypeParameterDeclaration( /* node */ typeParam, /* name */ typeParam.name, /* constraint */ constraint, - /* defaultType */ typeParam.default); + /* defaultType */ defaultType); }); } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts b/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts index 03d2b15b09..4857964057 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/test/type_parameter_emitter_spec.ts @@ -222,5 +222,32 @@ runInEachFileSystem(() => { expect(emitter.canEmit()).toBe(true); expect(emit(emitter)).toEqual(''); }); + + it('transforms generic type parameter defaults', () => { + const additionalFiles: TestFile[] = [{ + name: absoluteFrom('/node_modules/types/index.d.ts'), + contents: `export declare type MyType = string;`, + }]; + const emitter = createEmitter( + ` + import {MyType} from 'types'; + + export class TestClass {}`, + additionalFiles); + + expect(emitter.canEmit()).toBe(true); + expect(emit(emitter)).toEqual(''); + }); + + it('cannot emit when a type parameter default cannot be emitted', () => { + const emitter = createEmitter(` + interface Local {} + + export class TestClass {}`); + + expect(emitter.canEmit()).toBe(false); + expect(() => emit(emitter)) + .toThrowError('A type reference to emit must be imported from an absolute module'); + }); }); });