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

types: align with lib.dom.d.ts by removing [Symbol.toStringTag] from File/FormData #2968

Closed
wants to merge 1 commit into from

Conversation

jdufresne
Copy link
Contributor

This relates to...

#1172

Rationale

In TypeScript lib.dom.d.ts, the interfaces File and FormData do not include the [Symbol.toStringTag] instance method.

By aligning types, can avoid type errors such as the following when combining undici in a JSDom environment or other Browser like environments.

.../tests/utils/fetch.ts:99:3 - error TS2322: Type 'Mock<(resource: RequestInfo | URL, options?: RequestInit | undefined) => Promise<Response>>' is not assignable to type '{ (input: RequestInfo | URL, init?: RequestInit | undefined): Promise<Response>; (input: string | Request | URL, init?: RequestInit | undefined): Promise<...>; }'.
  Types of parameters 'options' and 'init' are incompatible.
    Type 'RequestInit | undefined' is not assignable to type 'import(".../node_modules/undici/types/fetch").RequestInit | undefined'.
      Type 'RequestInit' is not assignable to type 'import(".../node_modules/undici/types/fetch").RequestInit'.
        Types of property 'body' are incompatible.
          Type 'BodyInit | null | undefined' is not assignable to type 'BodyInit | undefined'.
            Type 'FormData' is not assignable to type 'BodyInit | undefined'.
              Property '[Symbol.toStringTag]' is missing in type 'FormData' but required in type 'import(".../node_modules/undici/types/formdata").FormData'.

99   globalThis.fetch = jest.fn(fetch);
     ~~~~~~~~~~~~~~~~

  node_modules/undici/types/formdata.d.ts:107:12
    107   readonly [Symbol.toStringTag]: string
                   ~~~~~~~~~~~~~~~~~~~~
    '[Symbol.toStringTag]' is declared here.
.../tests/utils/fetch.ts:99:3 - error TS2322: Type 'Mock<(resource: URL | RequestInfo, options?: RequestInit | undefined) => Promise<Response>>' is not assignable to type '{ (input: URL | RequestInfo, init?: RequestInit | undefined): Promise<Response>; (input: string | URL | Request, init?: RequestInit | undefined): Promise<...>; }'.
  Types of parameters 'options' and 'init' are incompatible.
    Type 'RequestInit | undefined' is not assignable to type 'import(".../node_modules/undici/types/fetch").RequestInit | undefined'.
      Type 'RequestInit' is not assignable to type 'import(".../node_modules/undici/types/fetch").RequestInit'.
        Types of property 'body' are incompatible.
          Type 'BodyInit | null | undefined' is not assignable to type 'BodyInit | undefined'.
            Type 'FormData' is not assignable to type 'BodyInit | undefined'.
              Type 'FormData' is not assignable to type 'import(".../node_modules/undici/types/formdata").FormData'.
                The types returned by 'get(...)' are incompatible between these types.
                  Type 'FormDataEntryValue | null' is not assignable to type 'import(".../node_modules/undici/types/formdata").FormDataEntryValue | null'.
                    Type 'File' is not assignable to type 'FormDataEntryValue | null'.
                      Property '[Symbol.toStringTag]' is missing in type 'File' but required in type 'import(".../node_modules/undici/types/file").File'.

99   globalThis.fetch = jest.fn(fetch);
     ~~~~~~~~~~~~~~~~

  node_modules/undici/types/file.d.ts:38:12
    38   readonly [Symbol.toStringTag]: string
                  ~~~~~~~~~~~~~~~~~~~~
    '[Symbol.toStringTag]' is declared here.

These types were both originally added in 5425b77 adnd then modified slightly in 609d89b.

The [Symbol.toStringTag] instance method is not something we expect users to call directly.

Changes

Removed the [Symbol.toStringTag] instance method from the File and FormData interfaces in the files file.d.ts and formdata.d.ts.

Features

N/A

Bug Fixes

N/A

Breaking Changes and Deprecations

N/A

Status

In TypeScript `lib.dom.d.ts`, the interfaces `File` and `FormData` do
not include the `[Symbol.toStringTag]` instance method.

By aligning types, can avoid type errors such as the following when
combining undici in a JSDom environment or other Browser like
environments.

```
.../tests/utils/fetch.ts:99:3 - error TS2322: Type 'Mock<(resource: RequestInfo | URL, options?: RequestInit | undefined) => Promise<Response>>' is not assignable to type '{ (input: RequestInfo | URL, init?: RequestInit | undefined): Promise<Response>; (input: string | Request | URL, init?: RequestInit | undefined): Promise<...>; }'.
  Types of parameters 'options' and 'init' are incompatible.
    Type 'RequestInit | undefined' is not assignable to type 'import(".../node_modules/undici/types/fetch").RequestInit | undefined'.
      Type 'RequestInit' is not assignable to type 'import(".../node_modules/undici/types/fetch").RequestInit'.
        Types of property 'body' are incompatible.
          Type 'BodyInit | null | undefined' is not assignable to type 'BodyInit | undefined'.
            Type 'FormData' is not assignable to type 'BodyInit | undefined'.
              Property '[Symbol.toStringTag]' is missing in type 'FormData' but required in type 'import(".../node_modules/undici/types/formdata").FormData'.

99   globalThis.fetch = jest.fn(fetch);
     ~~~~~~~~~~~~~~~~

  node_modules/undici/types/formdata.d.ts:107:12
    107   readonly [Symbol.toStringTag]: string
                   ~~~~~~~~~~~~~~~~~~~~
    '[Symbol.toStringTag]' is declared here.
```

```
.../tests/utils/fetch.ts:99:3 - error TS2322: Type 'Mock<(resource: URL | RequestInfo, options?: RequestInit | undefined) => Promise<Response>>' is not assignable to type '{ (input: URL | RequestInfo, init?: RequestInit | undefined): Promise<Response>; (input: string | URL | Request, init?: RequestInit | undefined): Promise<...>; }'.
  Types of parameters 'options' and 'init' are incompatible.
    Type 'RequestInit | undefined' is not assignable to type 'import(".../node_modules/undici/types/fetch").RequestInit | undefined'.
      Type 'RequestInit' is not assignable to type 'import(".../node_modules/undici/types/fetch").RequestInit'.
        Types of property 'body' are incompatible.
          Type 'BodyInit | null | undefined' is not assignable to type 'BodyInit | undefined'.
            Type 'FormData' is not assignable to type 'BodyInit | undefined'.
              Type 'FormData' is not assignable to type 'import(".../node_modules/undici/types/formdata").FormData'.
                The types returned by 'get(...)' are incompatible between these types.
                  Type 'FormDataEntryValue | null' is not assignable to type 'import(".../node_modules/undici/types/formdata").FormDataEntryValue | null'.
                    Type 'File' is not assignable to type 'FormDataEntryValue | null'.
                      Property '[Symbol.toStringTag]' is missing in type 'File' but required in type 'import(".../node_modules/undici/types/file").File'.

99   globalThis.fetch = jest.fn(fetch);
     ~~~~~~~~~~~~~~~~

  node_modules/undici/types/file.d.ts:38:12
    38   readonly [Symbol.toStringTag]: string
                  ~~~~~~~~~~~~~~~~~~~~
    '[Symbol.toStringTag]' is declared here.
```

These types were both originally added in
5425b77 adnd then modified slightly in
609d89b.

The `[Symbol.toStringTag]` instance method is not something we expect
users to call directly.
@KhafraDev
Copy link
Member

Can you add a test that ensures ts allows new FormData()[Symbol.toStringTag]?

@jdufresne
Copy link
Contributor Author

new FormData()[Symbol.toStringTag]

So, with this change, the above expression fails with typescript:

  test/types/formdata.test-d.ts:13:0
  ✖  13:0  Element implicitly has an any type because expression of type unique symbol can't be used to index type FormData.
  Property [SymbolConstructor.toStringTag] does not exist on type FormData.  

Does that mean you consider this PR incorrect?

Pardon my lack of knowledge here, but what is the use case for a library consumer would call this method. IIUC, this is an internal implementation detail for use by toString() and not something for library users.

The following does works in a browser:

const formData = new FormData();
formData[Symbol.toStringTag]
<- "FormData" 

But this property isn't defined on typescript's lib.dom.d.ts. I guess I'm asking, where should this difference be reconciled?

@KhafraDev
Copy link
Member

The webidl spec says that we should define Symbol.toStringTag on the object's prototypes. In the same way that Headers has a Symbol.iterator in its typings for example. The DOM types are wrong here.

@mcollina
Copy link
Member

@andrewbranch wdyt?

@andrewbranch
Copy link

@jdufresne
Copy link
Contributor Author

Thanks for all the feedback. I'll take a look at this upstream.

@jdufresne jdufresne closed this Mar 18, 2024
@jdufresne jdufresne deleted the types-toStringTag branch March 18, 2024 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants