typescript-go icon indicating copy to clipboard operation
typescript-go copied to clipboard

Type inference not behaving correctly using Jotai types

Open wojtekmaj opened this issue 1 month ago • 1 comments

Steps to reproduce

~I'm making every effort to make this a "minimal reproduction" but I'm still not happy with it. Sharing it nonetheless with the hope to update the playground with even simpler code.~

https://www.typescriptlang.org/play/?jsx=4#code/JYWwDg9gTgLgBAbzgQxhEcC+cBmV1wDkAVhDMsIQNwBQNokscMAnmAKaJwDK7M35GOwCCAYxjAIAOwA0cAOpRg5AEYAbEWgzY8BEmQrU6AemNwAKm3YBnGqw5wAQsmvsAIhFEBXEOynwAXkQaODgAfWAAEwAuOGsYJSkAc1pMWjsrOABZG2tkJM4g51cPb19-OAAyYNDrLxVidnFY+MSUmjS6e04ASSEQAVR2AB5zAD44IMVlZHVNdFG5AG1efkERcUkpUbGAXTkANwgosfTuuD72EGtBoR3JhSVVDWEtUaX9uBW+W42JaXeuz2h2OkVOJjMADFoCAMg5oVAQAAFfBgayjODsAAeQikkWsThc7k8Pj8MAmQQQIVwwHYanxsQAFMgoElrLEkDgYW5UMhYuYsABKSYTI5RWihZRXG7rWKXa6-e4AHwu-UV41S6RwXikm2kcARIAx2Nx+MJJRJ5XJjLCYFR7INMJREDRO2FVNCUD4XigUjgUi8ajUqToomk8RpdLNQRtLLZHNw3N5sRy1jyBSFIsQnRoYakEd8afyNl+D1QC1T6fYH2Wq1+Yn+20rxY+wLgYrBjJrcEZwoCEwQmEF6WxjHg2t1jcdiIAqlXezU4F6YD6-cNDZH6dYAghmazrH2JjhaVu92zBdgpQr1jvC1WZUNsMZwZgaEA

Behavior with [email protected]

No errors

Behavior with tsgo

src/file.tsx:33:41 - error TS2345: Argument of type '{ formData: BaseDocument; }' is not assignable to parameter of type '{ formData: Message; }'.
  Types of property 'formData' are incompatible.
    Type 'BaseDocument' is not assignable to type 'Message'.
      Property 'subject' is missing in type 'BaseDocument' but required in type '{ subject: string; }'.

33   return <Form fields={(args) => fields(args)} itemsState={messagesState} />;
                                           ~~~~

  src/file.tsx:11:3 - 'subject' is declared here.
    11   subject: string;
         ~~~~~~~

src/file.tsx:33:48 - error TS2322: Type 'WritableAtom<Message[], [SetStateAction<Message[]>], void> & WithInitialValue<Message[]>' is not assignable to type 'ItemState<BaseDocument> | ItemsState<BaseDocument>'.
  Type 'WritableAtom<Message[], [SetStateAction<Message[]>], void> & WithInitialValue<Message[]>' is not assignable to type 'ItemsState<BaseDocument>'.
    Types of property 'write' are incompatible.
      Type 'Write<[SetStateAction<Message[]>], void>' is not assignable to type 'Write<[SetStateAction<BaseDocument[]>], void>'.
        Types of parameters 'args' and 'args' are incompatible.
          Type 'SetStateAction<BaseDocument[]>' is not assignable to type 'SetStateAction<Message[]>'.
            Type 'BaseDocument[]' is not assignable to type 'SetStateAction<Message[]>'.
              Type 'BaseDocument[]' is not assignable to type 'Message[]'.
                Type 'BaseDocument' is not assignable to type 'Message'.
                  Property 'subject' is missing in type 'BaseDocument' but required in type '{ subject: string; }'.

33   return <Form fields={(args) => fields(args)} itemsState={messagesState} />;
                                                  ~~~~~~~~~~

  src/file.tsx:11:3 - 'subject' is declared here.
    11   subject: string;
         ~~~~~~~

  src/file.tsx:21:3 - The expected type comes from property 'itemsState' which is declared here on type 'IntrinsicAttributes & FormProps<BaseDocument>'
    21   itemsState: ItemsState<T> | ItemState<T>;
         ~~~~~~~~~~

wojtekmaj avatar Nov 20 '25 22:11 wojtekmaj

This seems to be a union ordering difference.

Swap the union type in itemsState and you'll see TS 5.9 errors (and I bet, tsgo would not): Playground Link

@ahejlsberg in case he has some insight into a fix or workaround we could apply for this.

jakebailey avatar Nov 20 '25 22:11 jakebailey