Skip to content

Default type T for InputFunction's TransformT#59649

Closed
angelaki wants to merge 3 commits intoangular:mainfrom
angelaki:DefaultTransform
Closed

Default type T for InputFunction's TransformT#59649
angelaki wants to merge 3 commits intoangular:mainfrom
angelaki:DefaultTransform

Conversation

@angelaki
Copy link
Contributor

@angelaki angelaki commented Jan 21, 2025

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.dev application / infrastructure changes
  • Other... Please describe:

Description

Curious why this isn't the default behavior so I'm quite sure there is a reason? Never the less, find it much more comfortable to not be forced to always write the type twice on using a converter:

multiple= input<boolean | 'append', boolean | 'append'>(true, { transform: v => v === 'append' ? 'append' : coerceBooleanProperty(v) });

-->

multiple = input<boolean | 'append'>(true, { transform: v => v === 'append' ? 'append' : coerceBooleanProperty(v) });

Does this PR introduce a breaking change?

  • Yes
  • No

@pullapprove pullapprove bot requested a review from crisbeto January 21, 2025 14:52
@JeanMeche
Copy link
Member

Why don't you just let the inference do it job ?

input(true, { transform: v => v === 'append' ? 'append' : booleanAttribute(v) }); is actually perfectly valid.

@angelaki
Copy link
Contributor Author

Why don't you just let the inference do it job ?

input(true, { transform: v => v === 'append' ? 'append' : booleanAttribute(v) }); is actually perfectly valid.

Oh wow, I actually wasn't aware of this! Thank you! But where is this magic? How does the signal know that it's value is not of the type of the first argument only? Never the less, would a default value hurt?

@JeanMeche
Copy link
Member

When the generic isn't specified, typescript will try to infer it.
But when there are multiple generics, and you specified only one of them, it won't do that and fail to find matching overload (with a single generic).

I wouldn't expect T to equal TransformT as the goal of the transform is to coerce a type, often unknown to another.

@angelaki
Copy link
Contributor Author

angelaki commented Jan 22, 2025

When the generic isn't specified, typescript will try to infer it. But when there are multiple generics, and you specified only one of them, it won't do that and fail to find matching overload (with a single generic).

I wouldn't expect T to equal TransformT as the goal of the transform is to coerce a type, often unknown to another.

I know about this infering but the values type is T - not TransformT. Never the less is the value of type TransformT - where / when is this happening?

But: right now, specifying only one type T, TransformT will fallback to undefined - that behavior would never be usefull, is it?

Edit: by the way, here the reason I created this PR: https://stackoverflow.com/questions/79082672/unable-to-add-types-to-input-with-transform-functionality

@pkozlowski-opensource pkozlowski-opensource requested review from JoostK and removed request for crisbeto January 22, 2025 16:15
@pullapprove pullapprove bot requested a review from crisbeto January 22, 2025 16:15
@JoostK
Copy link
Member

JoostK commented Jan 22, 2025

But: right now, specifying only one type T, TransformT will fallback to undefined - that behavior would never be usefull, is it?

This isn't the case; TypeScript requires that if some type arguments are present, then all non-optional type parameters must also have a corresponding type argument. A default type as introduced in this PR makes it valid, but only for atypical usages of transform: the output type is expected to be different from the input type.

Concretely, in your example you mention to have

multiple= input<boolean | 'append', boolean | 'append'>(true, { transform: v => v === 'append' ? 'append' : coerceBooleanProperty(v) });

this is unlikely what you intent to represent; e.g. the coerceBooleanProperty supports converting '' (the empty string) to a true value in support of attributes without value binding (which are assigned using the empty string), yet the '' is not part of your input type, so it's invalid according to this type. Hence, the entire transform becomes a no-op, as all values that inhabit the boolean | 'append' type are returned as-is.

This change also hinders potential advances in TypeScript that would be true solutions for this case, namely microsoft/TypeScript#54047 and microsoft/TypeScript#26349. It's unclear if such change will ever make it into TypeScript, but introducing a default value in Angular now will make such future feature inapplicable. Hence we do not want to go forward with this change.

@JoostK JoostK closed this Jan 22, 2025
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Feb 22, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants