Repository navigation
Issues around casting tuples to arrays #62177
Description
🔎 Search Terms
comparable relation casting comparison equality array tuple properties index infos
🕗 Version & Regression Information
- This is the behavior in every version I tried
⏯ Playground Link
💻 Code
interface ObjectLiteral {
[key: string]: any;
}
declare class Post {
id: number;
title: string;
}
declare const input1: (ObjectLiteral | null)[];
const casted1 = input1 as Post[]; // ok
declare const input2: [ObjectLiteral | null, ObjectLiteral | null];
const casted2 = input2 as Post[]; // errors, but the error is nonsensical given the mentioned types are very much comparable - as shown below
declare const input3: ObjectLiteral | null;
const casted3 = input3 as Post; // ok🙁 Actual behavior
the second cast fails and the user is left with a very confusing error given the third cast suceeds
🙂 Expected behavior
I'd expect the second cast to succeed
Additional information about the issue
In the compiler's code we can find this definition:
A type S is comparable to a type T if some (but not necessarily all) of the possible values of S are also possible values of T.
Under this definition, this cast should be allowed:
const value = [
{ id: 1, title: "foo" },
{ id: 2, title: "bar" },
] as const satisfies any[];
const input2: [ObjectLiteral | null, ObjectLiteral | null] = value; // ok
const castTarget2: Post[] = value; // okMore than that, some other related cases don't seem to adhere to this definition:
type PoorMansTuple = {
[K: number]: { x: number };
0: { x: number };
};
type PoorMansArray = {
[K: number]: { x: number; y: number };
};
declare const tupleLike: PoorMansTuple;
declare const arrayLike: PoorMansArray;
// Conversion of type 'PoorMansTuple' to type 'PoorMansArray' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
// 'number' index signatures are incompatible.
// Property 'y' is missing in type '{ x: number; }' but required in type '{ x: number; y: number; }'.(2352)
tupleLike as PoorMansArray;
// Conversion of type 'PoorMansArray' to type 'PoorMansTuple' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
// Property '0' is missing in type 'PoorMansArray' but required in type 'PoorMansTuple'.(2352)
arrayLike as PoorMansTuple;In those cases, the reported errors are also confusing. At the very least, a cast between types mentioned by the error on tupleLike as PoorMansArray is allowed. A missing property like it doesn't make a cast invalid.
This also extends to comparisons, given they also use comparable relation:
const x: [{ x: number; y: number }] = [{ x: 123, y: 456 }];
const tuple: [{ x: number }] = x; // ok
const array: { x: number; y: number }[] = x; // ok
// This comparison appears to be unintentional because the types '[{ x: number; }]' and '{ x: number; y: number; }[]' have no overlap.(2367)
if (tuple === array) {}Thanks to LukeAbby for discussing this stuff with me.
Activity
[-]Issues around casting arrays to tuples[/-][+]Issues around casting tuples to arrays[/+]RyanCavanaugh commentedon Aug 20, 2025
If there's some concrete code mistake making this happen I would look at the PR, but the repro as given doesn't really seem compelling. There is always going to be some gray area in what's an acceptable cast and what isn't. It doesn't seem worth dealing with the inevitable "oh no we tried to tweak something minor and it broke something actually important" fallout from trying to change this for the sake of a repro no one actually came forward with.
Andarist commentedon Aug 21, 2025
Fwiw, I found this because it's the reason behind a regression introduced by one of my PRs. The code sample there is more complex and more real-life.
typescript-bot commentedon Aug 24, 2025
This issue has been marked as "Not a Defect" and has seen no recent activity. It has been automatically closed for house-keeping purposes.