flowtype

Should Flow be marking this type as potentially `string`?


To me it should be a union of the string literals and not also string

type UnionType = {|type: "A"|} | {|type: "B"|} | {|type: "C"|}

const objectB: UnionType = {type: "B"}
const objectBType: "A" | "B" | "C" | string = objectB.type // no error
                                  // ^^^^^^  Why is this allowed?

https://flow.org/try/#0FDAuE8AcFMAIFUB2BLA9ogKlOBeWBvAHwhgC5YAiAQQsIF9ZCDjtyKAhWhpok6NgMJcQAY3QBnULFQAjAFbQRoduSRpM2WHnx82nOsDGJJ0+YuXisMAIxsajSpwcUhDyQCdkiAOZbTCpXYAOj5YAHow2ERUWGh3d1R3YFgU1LT0jMysiNgAPXyClIB1AAtwWGRxWFASytgAQwAbRtQAd2gAEwB+YCA


Solution

  • Flow is doing just what you've asked if it and nothing more. This is the same for instance as if you did

    class Parent{}
    class Child extends Parent {}
    
    const objectB: Child = new Child();
    const objectBType: Parent = child;
    

    So you are explicitly declaring objectBType to have the type Parent, which covers the type being assigned to it (Child), but also allows other types that extend Parent. Flow won't stop you from declaring the type as Parent even though the value assigned to it is Child. As long as the types are compatible, you can use a broader type.

    Since this variable is declared with const, there isn't any way for a different type to get in there, but if you want to declare the type to be broader, you can certainly do so.

    If it wasn't const, you could also imagine code like:

    type UnionType = {|type: "A"|} | {|type: "B"|} | {|type: "C"|}
    
    const objectB: UnionType = {type: "B"};
    
    let objectBType: "A" | "B" | "C" | string;
    if (Math.random() > 0.5) {
      objectBType = objectB.type;
    } else {
      objectBType = "foo";
    }
    

    so you might want to allow the specific set of types, or you might want to allow for a general string.

    Still sort of weird because string itself also covers "A" and the rest at a type level, but again that's more an issue with the specific types in this code, rather that with Flow's design.