Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat(core): allow passing undefined without needing to include it i…
…n the type argument of `input`

This commit introduces an overload for `input` to accept `undefined` as initial value if only
options are needed to be provided, inferring an input of type `T|undefined`. Prior to this change,
the type argument as specified needed to include `|undefined` explicitly even though that isn't
necessary when passing options isn't needed.

Relates to #53909
  • Loading branch information
JoostK committed Sep 1, 2024
commit ff25cabefd121d3d012fcc3b1b078432f6b529d7
2 changes: 2 additions & 0 deletions goldens/public-api/core/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,9 @@ export interface InputDecorator {
export interface InputFunction {
<T>(): InputSignal<T | undefined>;
<T>(initialValue: T, opts?: InputOptionsWithoutTransform<T>): InputSignal<T>;
<T>(initialValue: undefined, opts: InputOptionsWithoutTransform<T>): InputSignal<T | undefined>;
<T, TransformT>(initialValue: T, opts: InputOptionsWithTransform<T, TransformT>): InputSignalWithTransform<T, TransformT>;
<T, TransformT>(initialValue: undefined, opts: InputOptionsWithTransform<T | undefined, TransformT>): InputSignalWithTransform<T | undefined, TransformT>;
required: {
<T>(opts?: InputOptionsWithoutTransform<T>): InputSignal<T>;
<T, TransformT>(opts: InputOptionsWithTransform<T, TransformT>): InputSignalWithTransform<T, TransformT>;
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/authoring/input/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export interface InputFunction {
<T>(): InputSignal<T | undefined>;
/** Declares an input of type `T` with an explicit initial value. */
<T>(initialValue: T, opts?: InputOptionsWithoutTransform<T>): InputSignal<T>;
/** Declares an input of type `T|undefined` without an initial value, but with input options */
<T>(initialValue: undefined, opts: InputOptionsWithoutTransform<T>): InputSignal<T | undefined>;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to make opts required if an explicit undefined is passed, making input<string>(undefined) a type error, with the intention that that should always be achieved using just input<string>().

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if that is not confusing. TS error messages are not super great, but I like the incentive to encourage the shorthand.

/**
* Declares an input of type `T` with an initial value and a transform
* function.
Expand All @@ -62,6 +64,16 @@ export interface InputFunction {
initialValue: T,
opts: InputOptionsWithTransform<T, TransformT>,
): InputSignalWithTransform<T, TransformT>;
/**
* Declares an input of type `T|undefined` without an initial value and with a transform
* function.
*
* The input accepts values of type `TransformT` and the given
* transform function will transform the value to type `T|undefined`.
*/ <T, TransformT>(
initialValue: undefined,
opts: InputOptionsWithTransform<T | undefined, TransformT>,
): InputSignalWithTransform<T | undefined, TransformT>;

/**
* Initializes a required input.
Expand Down
18 changes: 18 additions & 0 deletions packages/core/test/authoring/signal_input_signature_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ export class InputSignatureTest {
/** string | undefined */
withNoInitialValue = input<string>();

/** undefined */
initialValueUndefinedWithoutOptions = input(undefined);
/** undefined */
initialValueUndefinedWithOptions = input(undefined, {});
/** @internal */
__shouldErrorIfInitialValueUndefinedExplicitReadWithoutOptions = input<string>(
// @ts-expect-error
undefined,
);
/** string | undefined, unknown */
initialValueUndefinedWithUntypedTransform = input(undefined, {transform: (bla) => ''});
/** string | undefined, string */
initialValueUndefinedWithTypedTransform = input(undefined, {transform: (bla: string) => ''});
/** string | undefined, string */
initialValueUndefinedExplicitReadWithTransform = input<string, string>(undefined, {
transform: (bla) => '',
});

/** string */
requiredNoInitialValue = input.required<string>();
/** string | undefined */
Expand Down