TypeScript does not throw an error at compile time for accessing an out-of-bounds index. Instead, it assumes that the value could be one of the types defined in the array (in this case, 1 or 2) or undefined.

TypeScript automatically infers the type of a value accessed from an array, even if that access is out of bounds. It assumes that the value could be one of the defined types or undefined, which can lead to confusion if you expect stricter enforcement of valid indices.

I just spent the last 2 hours trying to understand why I was getting a valid type from something that shouldn’t have been valid.

I think that the hate that JavaScript receives is well deserved, at least coming from Rust this is an absolute nightmare.

  • Feyd@programming.dev
    link
    fedilink
    arrow-up
    9
    ·
    25 days ago

    Your MyUnionType is defining an array (of any length) that only contains 1s and 2s. Setting values to [1,2] doesn’t narrow the type down to a tuple of 2. I’m not sure why you think it would, but feel free to explain your reasoning and maybe I can clarify your misunderstanding.

    In any case, it seems like you might be looking to use tuple types

    // this is an array that can contain 1s and 2s
    type ArrayOf1or2 = (1 | 2)[];
      
    
    // fine, because regardless of the length, it only contains 1s and 2s
    const ok1: ArrayOf1or2 = [1,1,1,2,2,2,1,2];
    
    // no good, because it can't have a 3
    const notok1: ArrayOf1or2 = [3];
    
    type Size2ArrayOf1sAnd2s = [(1 | 2), (1 | 2)];
    
    // has 2 so is fine
    const ok2: Size2ArrayOf1sAnd2s = [1,1];
    
    // has 1 so is not fine
    const notok2: Size2ArrayOf1sAnd2s = [1];
    
    // has 3 so is not fine
    const notok3: Size2ArrayOf1sAnd2s = [1,1,1];
    
  • hperrin@lemmy.ca
    link
    fedilink
    English
    arrow-up
    3
    ·
    25 days ago

    I’m sorry but your problem here is solely with JavaScript, not TypeScript. TS is right to assign that type to the value, because that is perfectly valid JS, and that is the type you should expect.

    It’s not hard to check for undefined and there are absolutely times you wouldn’t want an error to be thrown, so this is just you having a preference, and judging an entire language based on your preference.

    There are actual reasons to dislike how JS works, out of bounds array access returning undefined is not one of them.

    • hperrin@lemmy.ca
      link
      fedilink
      English
      arrow-up
      3
      ·
      25 days ago

      To add to my own comment, I want to remind you that JavaScript was designed to power websites, and having an entire website break because an array didn’t have anything in it yet is probably worse than the alternative.

      A lot of JS’ decisions actually make sense when you understand its history. That doesn’t mean it’s a great language, but it’s undeniably good at fulfilling its original purpose, making websites interactive in myriad different browser implementations.

      • dontblink@feddit.itOP
        link
        fedilink
        English
        arrow-up
        5
        ·
        25 days ago

        Yes you’re probably right, I definitely have bias and the time spent tryna fix the bug influenced this…

        Thanks

  • hallettj@leminal.space
    link
    fedilink
    English
    arrow-up
    3
    ·
    25 days ago

    You have two options depending on how you set your Typescript config.

    Option 1, the default:

    declare const xs: number[]
    const x = xs[4] // inferred type is `number`
    

    Option 2, using the noUncheckedIndexedAccess setting:

    declare const xs: number[]
    const x = xs[4] // inferred type is `number | undefined`
    

    Your AI assistant appears to assume option 2. Maybe you have that option enabled in your project?

    I’m sorry you had to spend a lot of time and frustration on this problem. But fundamentally Rust and Typescript have the same limitation: neither will catch out-of-bounds access errors on variable-length collections at type-checking time. They don’t have the necessary information to do that.

    Rust can catch out-of-bounds access on a fixed-length array if you use a literal number for the index access. But Typescript can do the same thing if you use a fixed-length tuple type (e.g. [number, number] instead of number[]).

  • Antithetical@lemmy.deedium.nl
    link
    fedilink
    arrow-up
    2
    ·
    edit-2
    25 days ago

    Could be that I misread but I think you’re misunderstanding types in Typescript.

    You have an array of 1 or 2 values of unbounded size. You put two values in but could have put 1000 in, your type doesn’t say anything about that. You can only put ones or twos in there though.

    I think your first line is equivalent to saying:

    type MyStringType = string[];
    

    I haven’t checked though so I might be wrong…

  • spit_evil_olive_tips@beehaw.org
    link
    fedilink
    arrow-up
    2
    ·
    25 days ago

    I’m having trouble following the example the LLM generated for you in your screenshot…I’m not terribly familiar with TypeScript but MyUnionType should be a union of types and instead it seems to be a union of…1 or 2?

    maybe you can share some example code of the unexpected behavior that you wrote, rather than something the fancy random number generator wrote?

  • JRaccoon@discuss.tchncs.de
    link
    fedilink
    arrow-up
    2
    ·
    25 days ago

    I don’t really get what you’re saying. JS doesn’t throw on out-of-bounds array access and instead returns undefined, even in Strict mode. Obviously TypeScript needs to match the actual behavior with the typing.

    const arr = [];
    arr[5]; // undefined