Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0ae6d81

Browse filesBrowse files
cexbrayatmattrbeck
authored andcommitted
fix(core): preserve explicit input transform write type
If a directive has an input declared as `dismissible = input<boolean>(true, {transform: booleanAttribute});` then the following templates were not compiling: ``` <div directiveName dismissible="true"></div> <div directiveName dismissible></div> ``` This commit fixes the issue, without breaking contravariant consumers.
1 parent 359fb50 commit 0ae6d81
Copy full SHA for 0ae6d81

5 files changed

+90-10Lines changed: 90 additions & 10 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎goldens/public-api/core/index.api.md‎

Copy file name to clipboardExpand all lines: goldens/public-api/core/index.api.md
+2-2Lines changed: 2 additions & 2 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1029,8 +1029,8 @@ export interface InputFunction {
10291029
<T>(initialValue: undefined, opts: InputOptionsWithoutTransform<T>): InputSignal<T | undefined>;
10301030
<T, TransformT>(initialValue: T, opts: InputOptionsWithTransform<T, TransformT>): InputSignalWithTransform<T, TransformT>;
10311031
<T, TransformT>(initialValue: undefined, opts: InputOptionsWithTransform<T | undefined, TransformT>): InputSignalWithTransform<T | undefined, TransformT>;
1032-
<T>(initialValue: T, opts: InputOptionsWithTransform<T, unknown>): InputSignalWithTransform<T, T>;
1033-
<T>(initialValue: undefined, opts: InputOptionsWithTransform<T | undefined, unknown>): InputSignalWithTransform<T | undefined, T | undefined>;
1032+
<T>(initialValue: T, opts: InputOptionsWithTransform<T, unknown>): InputSignalWithTransform<T, unknown>;
1033+
<T>(initialValue: undefined, opts: InputOptionsWithTransform<T | undefined, unknown>): InputSignalWithTransform<T | undefined, unknown>;
10341034
required: {
10351035
<T>(opts?: InputOptionsWithoutTransform<T>): InputSignal<T>;
10361036
<T, TransformT>(opts: InputOptionsWithTransform<T, TransformT>): InputSignalWithTransform<T, TransformT>;
Collapse file

‎packages/compiler-cli/test/ngtsc/authoring_inputs_spec.ts‎

Copy file name to clipboardExpand all lines: packages/compiler-cli/test/ngtsc/authoring_inputs_spec.ts
+58Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,64 @@ runInEachFileSystem(() => {
320320
);
321321
});
322322

323+
it('should allow text attributes for explicit signal inputs with booleanAttribute transform', () => {
324+
env.write(
325+
'test.ts',
326+
`
327+
import {booleanAttribute, Component, Directive, input} from '@angular/core';
328+
329+
@Directive({
330+
selector: '[directiveName]',
331+
})
332+
export class TestDir {
333+
dismissible = input<boolean>(true, {transform: booleanAttribute});
334+
}
335+
336+
@Component({
337+
template: \`
338+
<div directiveName [dismissible]="true"></div>
339+
<div directiveName dismissible="true"></div>
340+
<div directiveName dismissible></div>
341+
\`,
342+
imports: [TestDir],
343+
})
344+
export class TestComp {}
345+
`,
346+
);
347+
348+
const diagnostics = env.driveDiagnostics();
349+
expect(diagnostics).toEqual([]);
350+
});
351+
352+
it('should allow text attributes for explicit signal inputs with numberAttribute transform', () => {
353+
env.write(
354+
'test.ts',
355+
`
356+
import {Component, Directive, input, numberAttribute} from '@angular/core';
357+
358+
@Directive({
359+
selector: '[directiveName]',
360+
})
361+
export class TestDir {
362+
count = input<number>(0, {transform: numberAttribute});
363+
}
364+
365+
@Component({
366+
template: \`
367+
<div directiveName [count]="1"></div>
368+
<div directiveName count="1"></div>
369+
<div directiveName count=""></div>
370+
\`,
371+
imports: [TestDir],
372+
})
373+
export class TestComp {}
374+
`,
375+
);
376+
377+
const diagnostics = env.driveDiagnostics();
378+
expect(diagnostics).toEqual([]);
379+
});
380+
323381
it('should report unset required inputs', () => {
324382
env.write(
325383
'test.ts',
Collapse file

‎packages/core/src/authoring/input/input.ts‎

Copy file name to clipboardExpand all lines: packages/core/src/authoring/input/input.ts
+7-4Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,17 +79,20 @@ export interface InputFunction {
7979
): InputSignalWithTransform<T | undefined, TransformT>;
8080
/**
8181
* Declares an input of type `T` with an initial value and a transform function
82-
* that accepts values of the same type.
82+
* that accepts values of type `unknown`.
8383
*/
84-
<T>(initialValue: T, opts: InputOptionsWithTransform<T, unknown>): InputSignalWithTransform<T, T>;
84+
<T>(
85+
initialValue: T,
86+
opts: InputOptionsWithTransform<T, unknown>,
87+
): InputSignalWithTransform<T, unknown>;
8588
/**
8689
* Declares an input of type `T|undefined` without an initial value and with a transform
87-
* function that accepts values of the same type.
90+
* function that accepts values of type `unknown`.
8891
*/
8992
<T>(
9093
initialValue: undefined,
9194
opts: InputOptionsWithTransform<T | undefined, unknown>,
92-
): InputSignalWithTransform<T | undefined, T | undefined>;
95+
): InputSignalWithTransform<T | undefined, unknown>;
9396

9497
/**
9598
* Initializes a required input.
Collapse file

‎packages/core/test/authoring/signal_input_signature_test.ts‎

Copy file name to clipboardExpand all lines: packages/core/test/authoring/signal_input_signature_test.ts
+4-4Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,15 @@ export class InputSignatureTest {
102102
transform: (v: string | boolean) => '',
103103
});
104104

105-
/** boolean, boolean */
105+
/** boolean, unknown */
106106
explicitReadWithBooleanAttributeTransform = input<boolean>(false, {transform: booleanAttribute});
107-
/** number, number */
107+
/** number, unknown */
108108
explicitReadWithNumberAttributeTransform = input<number>(0, {transform: numberAttribute});
109-
/** boolean | undefined, boolean | undefined */
109+
/** boolean | undefined, unknown */
110110
explicitReadWithUndefinedInitialBooleanAttributeTransform = input<boolean>(undefined, {
111111
transform: booleanAttribute,
112112
});
113-
/** number | undefined, number | undefined */
113+
/** number | undefined, unknown */
114114
explicitReadWithUndefinedInitialNumberAttributeTransform = input<number>(undefined, {
115115
transform: numberAttribute,
116116
});
Collapse file

‎packages/forms/signals/test/web/form_field.spec.ts‎

Copy file name to clipboardExpand all lines: packages/forms/signals/test/web/form_field.spec.ts
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3978,6 +3978,25 @@ describe('field directive', () => {
39783978
});
39793979

39803980
describe('input transforms', () => {
3981+
it('should accept an explicit read type with InputSignalWithTransform', () => {
3982+
@Component({selector: 'custom-control', template: ``})
3983+
class CustomControl implements FormValueControl<string> {
3984+
readonly value = model('');
3985+
readonly disabled = input<boolean>(false, {transform: booleanAttribute});
3986+
}
3987+
3988+
@Component({
3989+
imports: [FormField, CustomControl],
3990+
template: `<custom-control [formField]="f" />`,
3991+
})
3992+
class TestCmp {
3993+
readonly f = form(signal(''));
3994+
}
3995+
3996+
const fixture = act(() => TestBed.createComponent(TestCmp));
3997+
expect(fixture.componentInstance).toBeDefined();
3998+
});
3999+
39814000
it('should accept InputSignal without transform', () => {
39824001
@Component({selector: 'custom-control', template: ``})
39834002
class CustomControl implements FormValueControl<string> {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.