Skip to content

Commit

Permalink
tweak behavior of tuples with rest elements
Browse files Browse the repository at this point in the history
  • Loading branch information
Andarist committed Apr 18, 2024
1 parent 4a45c4c commit 9d854aa
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 21 deletions.
6 changes: 6 additions & 0 deletions src/compiler/checker.ts
Expand Up @@ -13664,6 +13664,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

function forEachMappedTypePropertyKeyTypeAndIndexSignatureKeyType(type: Type, include: TypeFlags, stringsOnly: boolean, cb: (keyType: Type) => void) {
if (isTupleType(type)) {
if (type.target.hasRestElement) {
// key of any rest/variadic element is number
// it subsumes all potential leading fixed elements
cb(numberType);
return;
}
forEachType(getUnionType(getElementTypes(type).map((_, i) => getStringLiteralType("" + i))), cb);
return;
}
Expand Down
@@ -0,0 +1,66 @@
mappedTypeTupleConstraintTypeParameterInNameType.ts(45,7): error TS2322: Type 'string | number | bigint' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.
mappedTypeTupleConstraintTypeParameterInNameType.ts(46,7): error TS2322: Type 'string | number | bigint' is not assignable to type 'string'.
Type 'number' is not assignable to type 'string'.
mappedTypeTupleConstraintTypeParameterInNameType.ts(47,7): error TS2322: Type 'string | number | bigint' is not assignable to type 'bigint'.
Type 'string' is not assignable to type 'bigint'.


==== mappedTypeTupleConstraintTypeParameterInNameType.ts (3 errors) ====
// based on https://github.com/microsoft/TypeScript/issues/55762

declare class Decoder<T> {
decode(arrayBuffer: ArrayBuffer): T;
}

type ValueTypeOf<T extends Decoder<any>> = T extends Decoder<infer R>
? R
: never;

type StructDescriptor = ReadonlyArray<
readonly [key: string, type: Decoder<any>]
>;

type StructTypeFor<Descriptor extends StructDescriptor> = {
[K in keyof Descriptor as Descriptor[K][0]]: ValueTypeOf<Descriptor[K][1]>;
};

class StructDecoder<const Descriptor extends StructDescriptor> extends Decoder<
StructTypeFor<Descriptor>
> {
constructor(descriptor: Descriptor) {
super();
}
}

declare const i32Decoder: Decoder<number>;
declare const i64Decoder: Decoder<bigint>;

const structDecoder1 = new StructDecoder([
["a", i32Decoder],
["b", i64Decoder],
]);

const struct1 = structDecoder1.decode(new ArrayBuffer(100));

const v1_1: number = struct1.a;
const v1_2: bigint = struct1.b;

declare const descriptor2: [["a", Decoder<number>], ["b", Decoder<string>], ...["c", Decoder<bigint>][]]
const structDecoder2 = new StructDecoder(descriptor2);

const struct2 = structDecoder2.decode(new ArrayBuffer(100));

const v2_1: number = struct2.a; // error, rest element expands to index signature access
~~~~
!!! error TS2322: Type 'string | number | bigint' is not assignable to type 'number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
const v2_2: string = struct2.b; // error, rest element expands to index signature access
~~~~
!!! error TS2322: Type 'string | number | bigint' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
const v2_3: bigint = struct2.c; // error, rest element expands to index signature access
~~~~
!!! error TS2322: Type 'string | number | bigint' is not assignable to type 'bigint'.
!!! error TS2322: Type 'string' is not assignable to type 'bigint'.

Expand Up @@ -129,19 +129,19 @@ const struct2 = structDecoder2.decode(new ArrayBuffer(100));
>decode : Symbol(Decoder.decode, Decl(mappedTypeTupleConstraintTypeParameterInNameType.ts, 2, 26))
>ArrayBuffer : Symbol(ArrayBuffer, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))

const v2_1: number = struct2.a;
const v2_1: number = struct2.a; // error, rest element expands to index signature access
>v2_1 : Symbol(v2_1, Decl(mappedTypeTupleConstraintTypeParameterInNameType.ts, 44, 5))
>struct2.a : Symbol(a)
>struct2 : Symbol(struct2, Decl(mappedTypeTupleConstraintTypeParameterInNameType.ts, 42, 5))
>a : Symbol(a)

const v2_2: string = struct2.b;
const v2_2: string = struct2.b; // error, rest element expands to index signature access
>v2_2 : Symbol(v2_2, Decl(mappedTypeTupleConstraintTypeParameterInNameType.ts, 45, 5))
>struct2.b : Symbol(b)
>struct2 : Symbol(struct2, Decl(mappedTypeTupleConstraintTypeParameterInNameType.ts, 42, 5))
>b : Symbol(b)

const v2_3: bigint = struct2.c;
const v2_3: bigint = struct2.c; // error, rest element expands to index signature access
>v2_3 : Symbol(v2_3, Decl(mappedTypeTupleConstraintTypeParameterInNameType.ts, 46, 5))
>struct2.c : Symbol(c)
>struct2 : Symbol(struct2, Decl(mappedTypeTupleConstraintTypeParameterInNameType.ts, 42, 5))
Expand Down
Expand Up @@ -161,33 +161,33 @@ const struct2 = structDecoder2.decode(new ArrayBuffer(100));
>100 : 100
> : ^^^

const v2_1: number = struct2.a;
const v2_1: number = struct2.a; // error, rest element expands to index signature access
>v2_1 : number
> : ^^^^^^
>struct2.a : number
> : ^^^^^^
>struct2.a : string | number | bigint
> : ^^^^^^^^^^^^^^^^^^^^^^^^
>struct2 : StructTypeFor<[["a", Decoder<number>], ["b", Decoder<string>], ...["c", Decoder<bigint>][]]>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>a : number
> : ^^^^^^
>a : string | number | bigint
> : ^^^^^^^^^^^^^^^^^^^^^^^^

const v2_2: string = struct2.b;
const v2_2: string = struct2.b; // error, rest element expands to index signature access
>v2_2 : string
> : ^^^^^^
>struct2.b : string
> : ^^^^^^
>struct2.b : string | number | bigint
> : ^^^^^^^^^^^^^^^^^^^^^^^^
>struct2 : StructTypeFor<[["a", Decoder<number>], ["b", Decoder<string>], ...["c", Decoder<bigint>][]]>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>b : string
> : ^^^^^^
>b : string | number | bigint
> : ^^^^^^^^^^^^^^^^^^^^^^^^

const v2_3: bigint = struct2.c;
const v2_3: bigint = struct2.c; // error, rest element expands to index signature access
>v2_3 : bigint
> : ^^^^^^
>struct2.c : bigint
> : ^^^^^^
>struct2.c : string | number | bigint
> : ^^^^^^^^^^^^^^^^^^^^^^^^
>struct2 : StructTypeFor<[["a", Decoder<number>], ["b", Decoder<string>], ...["c", Decoder<bigint>][]]>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>c : bigint
> : ^^^^^^
>c : string | number | bigint
> : ^^^^^^^^^^^^^^^^^^^^^^^^

Expand Up @@ -45,6 +45,6 @@ const structDecoder2 = new StructDecoder(descriptor2);

const struct2 = structDecoder2.decode(new ArrayBuffer(100));

const v2_1: number = struct2.a;
const v2_2: string = struct2.b;
const v2_3: bigint = struct2.c;
const v2_1: number = struct2.a; // error, rest element expands to index signature access
const v2_2: string = struct2.b; // error, rest element expands to index signature access
const v2_3: bigint = struct2.c; // error, rest element expands to index signature access

0 comments on commit 9d854aa

Please sign in to comment.