fix(ivy): allow directive inheritance in strict mode (#28634)
For TypeScript compilation units that have the "strictFunctionTypes" option enabled, an error would be produced for Ivy's definition fields in declaration files in the case of inheritance across directives or pipes. This change loosens the definition types to allow for subtypes of the defined type where necessary. A test package that has the "strict" option enabled verifies that we won't regress in environments where strict type checking is enabled. Fixes #28079 PR Close #28634
This commit is contained in:
@ -184,7 +184,7 @@ describe('di', () => {
|
||||
consts: 0,
|
||||
vars: 0,
|
||||
factory: () => new Comp(directiveInject(DirB)),
|
||||
template: (ctx: any, fm: boolean) => {}
|
||||
template: (rf: RenderFlags, ctx: Comp) => {}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
|
||||
import {ElementRef, Inject, InjectionToken, QueryList, ɵAttributeMarker as AttributeMarker} from '../../src/core';
|
||||
import {ComponentDef, DirectiveDef, InheritDefinitionFeature, NgOnChangesFeature, ProvidersFeature, RenderFlags, allocHostVars, bind, contentQuery, defineBase, defineComponent, defineDirective, directiveInject, element, elementEnd, elementProperty, elementStart, load, loadContentQuery, loadViewQuery, queryRefresh, viewQuery} from '../../src/render3/index';
|
||||
import {allocHostVars, bind, ComponentDef, contentQuery, defineBase, defineComponent, defineDirective, DirectiveDef, directiveInject, element, elementEnd, elementProperty, elementStart, InheritDefinitionFeature, load, loadContentQuery, loadViewQuery, NgOnChangesFeature, ProvidersFeature, queryRefresh, RenderFlags, viewQuery,} from '../../src/render3/index';
|
||||
|
||||
import {ComponentFixture, createComponent, getDirectiveOnNode} from './render_util';
|
||||
|
||||
@ -457,8 +457,8 @@ describe('InheritDefinitionFeature', () => {
|
||||
consts: 0,
|
||||
vars: 0,
|
||||
selectors: [['', 'subDir', '']],
|
||||
viewQuery: (directiveIndex: number, elementIndex: number) => {
|
||||
log.push(['sub', directiveIndex, elementIndex]);
|
||||
viewQuery: (rf: RenderFlags, ctx: SubComponent) => {
|
||||
log.push(['sub', rf, ctx]);
|
||||
},
|
||||
factory: () => new SubComponent(),
|
||||
features: [InheritDefinitionFeature]
|
||||
@ -469,9 +469,10 @@ describe('InheritDefinitionFeature', () => {
|
||||
|
||||
const context = {foo: 'bar'};
|
||||
|
||||
subDef.viewQuery !(1, context);
|
||||
subDef.viewQuery !(RenderFlags.Create, context);
|
||||
|
||||
expect(log).toEqual([['super', 1, context], ['sub', 1, context]]);
|
||||
expect(log).toEqual(
|
||||
[['super', RenderFlags.Create, context], ['sub', RenderFlags.Create, context]]);
|
||||
});
|
||||
|
||||
|
||||
|
23
packages/core/test/strict_types/BUILD.bazel
Normal file
23
packages/core/test/strict_types/BUILD.bazel
Normal file
@ -0,0 +1,23 @@
|
||||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
load("//tools:defaults.bzl", "jasmine_node_test", "ts_library")
|
||||
|
||||
ts_library(
|
||||
name = "strict_types_lib",
|
||||
testonly = True,
|
||||
srcs = glob(
|
||||
["**/*.ts"],
|
||||
),
|
||||
tsconfig = ":tsconfig.json",
|
||||
deps = [
|
||||
"//packages/core",
|
||||
],
|
||||
)
|
||||
|
||||
jasmine_node_test(
|
||||
name = "strict_types",
|
||||
deps = [
|
||||
":strict_types_lib",
|
||||
"//tools/testing:node",
|
||||
],
|
||||
)
|
37
packages/core/test/strict_types/inheritance_spec.ts
Normal file
37
packages/core/test/strict_types/inheritance_spec.ts
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ɵComponentDefWithMeta as ComponentDefWithMeta, ɵPipeDefWithMeta as PipeDefWithMeta} from '@angular/core';
|
||||
|
||||
declare class SuperComponent {
|
||||
static ngComponentDef: ComponentDefWithMeta<SuperComponent, '[super]', never, {}, {}, never>;
|
||||
}
|
||||
|
||||
declare class SubComponent extends SuperComponent {
|
||||
// Declaring a field in the subtype makes its structure incompatible with that of the
|
||||
// supertype. Special care needs to be taken in Ivy's definition types, or TypeScript
|
||||
// would produce type errors when the "strictFunctionTypes" option is enabled.
|
||||
onlyInSubtype: string;
|
||||
|
||||
static ngComponentDef: ComponentDefWithMeta<SubComponent, '[sub]', never, {}, {}, never>;
|
||||
}
|
||||
|
||||
declare class SuperPipe { static ngPipeDef: PipeDefWithMeta<SuperPipe, 'super'>; }
|
||||
|
||||
declare class SubPipe extends SuperPipe {
|
||||
onlyInSubtype: string;
|
||||
|
||||
static ngPipeDef: PipeDefWithMeta<SubPipe, 'sub'>;
|
||||
}
|
||||
|
||||
describe('inheritance strict type checking', () => {
|
||||
// Verify that Ivy definition fields in declaration files conform to TypeScript's strict
|
||||
// type checking constraints in the case of inheritance across directives/components/pipes.
|
||||
// https://github.com/angular/angular/issues/28079
|
||||
it('should compile without errors', () => {});
|
||||
});
|
6
packages/core/test/strict_types/tsconfig.json
Normal file
6
packages/core/test/strict_types/tsconfig.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../../tsconfig-test.json",
|
||||
"compilerOptions": {
|
||||
"strict": true
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user