Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow constructing URLSearchParams directly from FormData #30584

Closed
thatbudakguy opened this issue Mar 25, 2019 · 17 comments
Closed

allow constructing URLSearchParams directly from FormData #30584

thatbudakguy opened this issue Mar 25, 2019 · 17 comments
Labels
Bug A bug in TypeScript Domain: lib.d.ts The issue relates to the different libraries shipped with TypeScript
Milestone

Comments

@thatbudakguy
Copy link

TypeScript Version: 3.4.0-dev.20190323

Search Terms:
URLSearchParams, FormData

Code

let form = document.createElement('form')
console.log(new URLSearchParams(new FormData(form)))

Expected behavior:
compilation succeeds and an (empty) URLSearchParams instance is constructed using the provided FormData. The above code runs without issue on Chrome 73 and Firefox 67 for me.

Actual behavior:
compilation fails because URLSearchParams doesn't explicitly allow an argument of type FormData as input to the constructor.

Argument of type 'FormData' is not assignable to parameter of type 'string | Record<string, string> | URLSearchParams | string[][]'.
  Property 'sort' is missing in type 'FormData' but required in type 'URLSearchParams'.

Playground Link:
link

Related Issues:
#12517
#15338

@RyanCavanaugh RyanCavanaugh added Bug A bug in TypeScript Domain: lib.d.ts The issue relates to the different libraries shipped with TypeScript labels Mar 25, 2019
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Mar 25, 2019
@thatbudakguy
Copy link
Author

If all that's required for this is to add | FormData to the constructor signature, I'm happy to PR.

@saschanaz
Copy link
Contributor

#19806 covers this.

@leonstafford
Copy link

@thatbudakguy - in the meantime, do you have a workaround for this?

@thatbudakguy
Copy link
Author

@leonstafford my current workaround is just // @ts-ignore, sadly.

@raythurnevoid
Copy link

Another workaround is: new URLSearchParams(new FormData(event.currentTarget) as any)

@JirkaDellOro
Copy link

Is there a deadline for this bug to be fixed?

@JirkaDellOro
Copy link

No? Yes? When?

@Spongman
Copy link

any news?

sstephenson added a commit to hotwired/turbo that referenced this issue Jan 29, 2021
Although Chrome, Firefox, and Safari all seem to implement support for `new URLSearchParams(formData)`, the [spec][1] doesn’t mention it, the IDL and [TypeScript][2] don’t have typings for it, and searching suggests it’s a recent addition.

[1]: https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
[2]: microsoft/TypeScript#30584
@PaperStrike
Copy link

PaperStrike commented Aug 1, 2021

I don't think it will be "fixed" as FormData may contain File while URLSearchParams only accepts String.

That code runs successfully in browsers by the implicit conversions in JS. Explicit matched types are needed in TS. Try to filter out the Files, or convert them to Strings. For example,

// For files, use their names
const convertedFormEntries = Array.from(
  new FormData(),
  ([key, value]) => (
    [key, typeof value === 'string' ? value : value.name]
  ),
);
const searchParams = new URLSearchParams(convertedFormEntries);

You can see the error more clearly in this TS playground.

@JirkaDellOro
Copy link

Well, MDN writes that the constructor accepts one the following:

  • A USVString, which will be parsed from application/x-www-form-urlencoded format. A leading '?' character is ignored.
  • A literal sequence of name-value string pairs, or any object — such as a FormData object — with an iterator that produces a sequence of string pairs. Note that that File entries will be serialized as [object File] rather than as their filename (as they would in an application/x-www-form-urlencoded form).
  • A record of USVString keys and USVString values.

Since FormData is explicitly mentioned, TypeScript should gladly compile it and the definition file for the dom should include the mentioned types in the constructors signature. The fact that file won't show a filename but [object File] is a logical problem at runtime, not at compiletime.

https://jsfiddle.net/3ng6qkL1/

@saschanaz
Copy link
Contributor

saschanaz commented Aug 1, 2021

The fact that file won't show a filename but [object File] is a logical problem at runtime, not at compiletime.

And TypeScript is all for preventing such logical typing problems.

Maybe FormData could be made generic so that this can work:

const data = new FormData<string>();
console.log(new URLSearchParams(data));

I'm not sure new FormData<string>(formElement) makes sense since the element may include non-strings.

@JirkaDellOro
Copy link

And TypeScript is all for preventing such logical typing problems.

True, On the other hand, TypeScript should not prevent standard functionality to work as intended.

@PaperStrike
Copy link

PaperStrike commented Aug 1, 2021

MDN isn't the standard, strictly speaking.

The file name conversion is defined in form entry list to name-value pairs conversion, HTML Standard. Click on the second bold sentence, it shows where it is used.

The note about [object File] isn't mentioned anywhere in steps to initialize a URLSearchParams, URL Standard.
It happens by implicit conversions.

@JirkaDellOro
Copy link

Now let me perform an elegant 180 after digging into it. This issue should not be labeled bug but works as intended and praised as a feature of TypeScript.

@thatbudakguy
Copy link
Author

closing, since as others have mentioned it's not a bug for TypeScript to avoid coercing File despite this being common behavior elsewhere. thread offers several workarounds for anyone still looking to do this.

@sacru2red
Copy link

sacru2red commented Jan 3, 2023

Negated types feature could clear it. in future
any not File

or
FormData methods should take a Generic #43797

@lightyaer
Copy link

Another workaround:

  const formData = new FormData();
  formData.set('something', "something");

  const searchParams = new URLSearchParams(
    formData as unknown as Record<string, string>,
  ).toString();

if value is an object, then JSON.stringify(object);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: lib.d.ts The issue relates to the different libraries shipped with TypeScript
Projects
None yet
Development

No branches or pull requests

10 participants