Only infer readonly tuples for const type parameters when constraints permit (#55229)

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
This commit is contained in:
Anders Hejlsberg
2023-08-26 08:20:55 -07:00
committed by GitHub
parent 51e7a34c2c
commit 753c463821
6 changed files with 854 additions and 5 deletions

View File

@@ -23674,6 +23674,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return isArrayType(type) || !(type.flags & TypeFlags.Nullable) && isTypeAssignableTo(type, anyReadonlyArrayType);
}
function isMutableArrayLikeType(type: Type): boolean {
// A type is mutable-array-like if it is a reference to the global Array type, or if it is not the
// any, undefined or null type and if it is assignable to Array<any>
return isMutableArrayOrTuple(type) || !(type.flags & (TypeFlags.Any | TypeFlags.Nullable)) && isTypeAssignableTo(type, anyArrayType);
}
function getSingleBaseForNonAugmentingSubtype(type: Type) {
if (!(getObjectFlags(type) & ObjectFlags.Reference) || !(getObjectFlags((type as TypeReference).target) & ObjectFlags.ClassOrInterface)) {
return undefined;
@@ -24338,7 +24344,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
callback(getTypeAtPosition(source, i), getTypeAtPosition(target, i));
}
if (targetRestType) {
callback(getRestTypeAtPosition(source, paramCount), targetRestType);
callback(getRestTypeAtPosition(source, paramCount, /*readonly*/ isConstTypeVariable(targetRestType) && !someType(targetRestType, isMutableArrayLikeType)), targetRestType);
}
}
@@ -30541,7 +30547,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return createTupleType(elementTypes, elementFlags);
}
if (forceTuple || inConstContext || inTupleContext) {
return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext));
return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext && !(contextualType && someType(contextualType, isMutableArrayLikeType))));
}
return createArrayLiteralType(createArrayType(
elementTypes.length ?
@@ -33139,7 +33145,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
names.push((arg as SyntheticExpression).tupleNameSource!);
}
}
return createTupleType(types, flags, inConstContext, length(names) === length(types) ? names : undefined);
return createTupleType(types, flags, inConstContext && !someType(restType, isMutableArrayLikeType), length(names) === length(types) ? names : undefined);
}
function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined {
@@ -35455,7 +35461,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return undefined;
}
function getRestTypeAtPosition(source: Signature, pos: number): Type {
function getRestTypeAtPosition(source: Signature, pos: number, readonly?: boolean): Type {
const parameterCount = getParameterCount(source);
const minArgumentCount = getMinArgumentCount(source);
const restType = getEffectiveRestType(source);
@@ -35479,7 +35485,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
names.push(name);
}
}
return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined);
return createTupleType(types, flags, readonly, length(names) === length(types) ? names : undefined);
}
// Return the number of parameters in a signature. The rest parameter, if present, counts as one

View File

@@ -107,4 +107,87 @@ typeParameterConstModifiers.ts(55,9): error TS1277: 'const' modifier can only ap
const thingMapped = <const O extends Record<string, any>>(o: NotEmptyMapped<O>) => o;
const tMapped = thingMapped({ foo: '' }); // { foo: "" }
// repro from https://github.com/microsoft/TypeScript/issues/55033
function factory_55033_minimal<const T extends readonly unknown[]>(cb: (...args: T) => void) {
return {} as T
}
const test_55033_minimal = factory_55033_minimal((b: string) => {})
function factory_55033<const T extends readonly unknown[]>(cb: (...args: T) => void) {
return function call<const K extends T>(...args: K): K {
return {} as K;
};
}
const t1_55033 = factory_55033((a: { test: number }, b: string) => {})(
{ test: 123 },
"some string"
);
const t2_55033 = factory_55033((a: { test: number }, b: string) => {})(
{ test: 123 } as const,
"some string"
);
// Same with non-readonly constraint
function factory_55033_2<const T extends unknown[]>(cb: (...args: T) => void) {
return function call<const K extends T>(...args: K): K {
return {} as K;
};
}
const t1_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
{ test: 123 },
"some string"
);
const t2_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
{ test: 123 } as const,
"some string"
);
// Repro from https://github.com/microsoft/TypeScript/issues/51931
declare function fn<const T extends any[]>(...args: T): T;
const a = fn("a", false);
// More examples of non-readonly constraints
declare function fa1<const T extends unknown[]>(args: T): T;
declare function fa2<const T extends readonly unknown[]>(args: T): T;
fa1(["hello", 42]);
fa2(["hello", 42]);
declare function fb1<const T extends unknown[]>(...args: T): T;
declare function fb2<const T extends readonly unknown[]>(...args: T): T;
fb1("hello", 42);
fb2("hello", 42);
declare function fc1<const T extends unknown[]>(f: (...args: T) => void, ...args: T): T;
declare function fc2<const T extends readonly unknown[]>(f: (...args: T) => void, ...args: T): T;
fc1((a: string, b: number) => {}, "hello", 42);
fc2((a: string, b: number) => {}, "hello", 42);
declare function fd1<const T extends string[] | number[]>(args: T): T;
declare function fd2<const T extends string[] | readonly number[]>(args: T): T;
declare function fd3<const T extends readonly string[] | readonly number[]>(args: T): T;
fd1(["hello", "world"]);
fd1([1, 2, 3]);
fd2(["hello", "world"]);
fd2([1, 2, 3]);
fd3(["hello", "world"]);
fd3([1, 2, 3]);
declare function fn1<const T extends { foo: unknown[] }[]>(...args: T): T;
fn1({ foo: ["hello", 123] }, { foo: [true]});

View File

@@ -101,6 +101,89 @@ type NotEmptyMapped<T extends Record<string, any>> = keyof T extends never ? nev
const thingMapped = <const O extends Record<string, any>>(o: NotEmptyMapped<O>) => o;
const tMapped = thingMapped({ foo: '' }); // { foo: "" }
// repro from https://github.com/microsoft/TypeScript/issues/55033
function factory_55033_minimal<const T extends readonly unknown[]>(cb: (...args: T) => void) {
return {} as T
}
const test_55033_minimal = factory_55033_minimal((b: string) => {})
function factory_55033<const T extends readonly unknown[]>(cb: (...args: T) => void) {
return function call<const K extends T>(...args: K): K {
return {} as K;
};
}
const t1_55033 = factory_55033((a: { test: number }, b: string) => {})(
{ test: 123 },
"some string"
);
const t2_55033 = factory_55033((a: { test: number }, b: string) => {})(
{ test: 123 } as const,
"some string"
);
// Same with non-readonly constraint
function factory_55033_2<const T extends unknown[]>(cb: (...args: T) => void) {
return function call<const K extends T>(...args: K): K {
return {} as K;
};
}
const t1_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
{ test: 123 },
"some string"
);
const t2_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
{ test: 123 } as const,
"some string"
);
// Repro from https://github.com/microsoft/TypeScript/issues/51931
declare function fn<const T extends any[]>(...args: T): T;
const a = fn("a", false);
// More examples of non-readonly constraints
declare function fa1<const T extends unknown[]>(args: T): T;
declare function fa2<const T extends readonly unknown[]>(args: T): T;
fa1(["hello", 42]);
fa2(["hello", 42]);
declare function fb1<const T extends unknown[]>(...args: T): T;
declare function fb2<const T extends readonly unknown[]>(...args: T): T;
fb1("hello", 42);
fb2("hello", 42);
declare function fc1<const T extends unknown[]>(f: (...args: T) => void, ...args: T): T;
declare function fc2<const T extends readonly unknown[]>(f: (...args: T) => void, ...args: T): T;
fc1((a: string, b: number) => {}, "hello", 42);
fc2((a: string, b: number) => {}, "hello", 42);
declare function fd1<const T extends string[] | number[]>(args: T): T;
declare function fd2<const T extends string[] | readonly number[]>(args: T): T;
declare function fd3<const T extends readonly string[] | readonly number[]>(args: T): T;
fd1(["hello", "world"]);
fd1([1, 2, 3]);
fd2(["hello", "world"]);
fd2([1, 2, 3]);
fd3(["hello", "world"]);
fd3([1, 2, 3]);
declare function fn1<const T extends { foo: unknown[] }[]>(...args: T): T;
fn1({ foo: ["hello", 123] }, { foo: [true]});
//// [typeParameterConstModifiers.js]
@@ -154,3 +237,45 @@ var thing = function (o) { return o; };
var t = thing({ foo: '' }); // readonly { foo: "" }
var thingMapped = function (o) { return o; };
var tMapped = thingMapped({ foo: '' }); // { foo: "" }
// repro from https://github.com/microsoft/TypeScript/issues/55033
function factory_55033_minimal(cb) {
return {};
}
var test_55033_minimal = factory_55033_minimal(function (b) { });
function factory_55033(cb) {
return function call() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return {};
};
}
var t1_55033 = factory_55033(function (a, b) { })({ test: 123 }, "some string");
var t2_55033 = factory_55033(function (a, b) { })({ test: 123 }, "some string");
// Same with non-readonly constraint
function factory_55033_2(cb) {
return function call() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return {};
};
}
var t1_55033_2 = factory_55033_2(function (a, b) { })({ test: 123 }, "some string");
var t2_55033_2 = factory_55033_2(function (a, b) { })({ test: 123 }, "some string");
var a = fn("a", false);
fa1(["hello", 42]);
fa2(["hello", 42]);
fb1("hello", 42);
fb2("hello", 42);
fc1(function (a, b) { }, "hello", 42);
fc2(function (a, b) { }, "hello", 42);
fd1(["hello", "world"]);
fd1([1, 2, 3]);
fd2(["hello", "world"]);
fd2([1, 2, 3]);
fd3(["hello", "world"]);
fd3([1, 2, 3]);
fn1({ foo: ["hello", 123] }, { foo: [true] });

View File

@@ -361,3 +361,256 @@ const tMapped = thingMapped({ foo: '' }); // { foo: "" }
>thingMapped : Symbol(thingMapped, Decl(typeParameterConstModifiers.ts, 97, 5))
>foo : Symbol(foo, Decl(typeParameterConstModifiers.ts, 99, 29))
// repro from https://github.com/microsoft/TypeScript/issues/55033
function factory_55033_minimal<const T extends readonly unknown[]>(cb: (...args: T) => void) {
>factory_55033_minimal : Symbol(factory_55033_minimal, Decl(typeParameterConstModifiers.ts, 99, 41))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 103, 31))
>cb : Symbol(cb, Decl(typeParameterConstModifiers.ts, 103, 67))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 103, 72))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 103, 31))
return {} as T
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 103, 31))
}
const test_55033_minimal = factory_55033_minimal((b: string) => {})
>test_55033_minimal : Symbol(test_55033_minimal, Decl(typeParameterConstModifiers.ts, 107, 5))
>factory_55033_minimal : Symbol(factory_55033_minimal, Decl(typeParameterConstModifiers.ts, 99, 41))
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 107, 50))
function factory_55033<const T extends readonly unknown[]>(cb: (...args: T) => void) {
>factory_55033 : Symbol(factory_55033, Decl(typeParameterConstModifiers.ts, 107, 67))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 109, 23))
>cb : Symbol(cb, Decl(typeParameterConstModifiers.ts, 109, 59))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 109, 64))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 109, 23))
return function call<const K extends T>(...args: K): K {
>call : Symbol(call, Decl(typeParameterConstModifiers.ts, 110, 10))
>K : Symbol(K, Decl(typeParameterConstModifiers.ts, 110, 25))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 109, 23))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 110, 44))
>K : Symbol(K, Decl(typeParameterConstModifiers.ts, 110, 25))
>K : Symbol(K, Decl(typeParameterConstModifiers.ts, 110, 25))
return {} as K;
>K : Symbol(K, Decl(typeParameterConstModifiers.ts, 110, 25))
};
}
const t1_55033 = factory_55033((a: { test: number }, b: string) => {})(
>t1_55033 : Symbol(t1_55033, Decl(typeParameterConstModifiers.ts, 115, 5))
>factory_55033 : Symbol(factory_55033, Decl(typeParameterConstModifiers.ts, 107, 67))
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 115, 32))
>test : Symbol(test, Decl(typeParameterConstModifiers.ts, 115, 36))
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 115, 52))
{ test: 123 },
>test : Symbol(test, Decl(typeParameterConstModifiers.ts, 116, 5))
"some string"
);
const t2_55033 = factory_55033((a: { test: number }, b: string) => {})(
>t2_55033 : Symbol(t2_55033, Decl(typeParameterConstModifiers.ts, 120, 5))
>factory_55033 : Symbol(factory_55033, Decl(typeParameterConstModifiers.ts, 107, 67))
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 120, 32))
>test : Symbol(test, Decl(typeParameterConstModifiers.ts, 120, 36))
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 120, 52))
{ test: 123 } as const,
>test : Symbol(test, Decl(typeParameterConstModifiers.ts, 121, 5))
>const : Symbol(const)
"some string"
);
// Same with non-readonly constraint
function factory_55033_2<const T extends unknown[]>(cb: (...args: T) => void) {
>factory_55033_2 : Symbol(factory_55033_2, Decl(typeParameterConstModifiers.ts, 123, 2))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 127, 25))
>cb : Symbol(cb, Decl(typeParameterConstModifiers.ts, 127, 52))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 127, 57))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 127, 25))
return function call<const K extends T>(...args: K): K {
>call : Symbol(call, Decl(typeParameterConstModifiers.ts, 128, 10))
>K : Symbol(K, Decl(typeParameterConstModifiers.ts, 128, 25))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 127, 25))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 128, 44))
>K : Symbol(K, Decl(typeParameterConstModifiers.ts, 128, 25))
>K : Symbol(K, Decl(typeParameterConstModifiers.ts, 128, 25))
return {} as K;
>K : Symbol(K, Decl(typeParameterConstModifiers.ts, 128, 25))
};
}
const t1_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
>t1_55033_2 : Symbol(t1_55033_2, Decl(typeParameterConstModifiers.ts, 133, 5))
>factory_55033_2 : Symbol(factory_55033_2, Decl(typeParameterConstModifiers.ts, 123, 2))
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 133, 36))
>test : Symbol(test, Decl(typeParameterConstModifiers.ts, 133, 40))
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 133, 56))
{ test: 123 },
>test : Symbol(test, Decl(typeParameterConstModifiers.ts, 134, 5))
"some string"
);
const t2_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
>t2_55033_2 : Symbol(t2_55033_2, Decl(typeParameterConstModifiers.ts, 138, 5))
>factory_55033_2 : Symbol(factory_55033_2, Decl(typeParameterConstModifiers.ts, 123, 2))
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 138, 36))
>test : Symbol(test, Decl(typeParameterConstModifiers.ts, 138, 40))
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 138, 56))
{ test: 123 } as const,
>test : Symbol(test, Decl(typeParameterConstModifiers.ts, 139, 5))
>const : Symbol(const)
"some string"
);
// Repro from https://github.com/microsoft/TypeScript/issues/51931
declare function fn<const T extends any[]>(...args: T): T;
>fn : Symbol(fn, Decl(typeParameterConstModifiers.ts, 141, 2))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 145, 20))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 145, 43))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 145, 20))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 145, 20))
const a = fn("a", false);
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 147, 5))
>fn : Symbol(fn, Decl(typeParameterConstModifiers.ts, 141, 2))
// More examples of non-readonly constraints
declare function fa1<const T extends unknown[]>(args: T): T;
>fa1 : Symbol(fa1, Decl(typeParameterConstModifiers.ts, 147, 25))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 151, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 151, 48))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 151, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 151, 21))
declare function fa2<const T extends readonly unknown[]>(args: T): T;
>fa2 : Symbol(fa2, Decl(typeParameterConstModifiers.ts, 151, 60))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 152, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 152, 57))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 152, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 152, 21))
fa1(["hello", 42]);
>fa1 : Symbol(fa1, Decl(typeParameterConstModifiers.ts, 147, 25))
fa2(["hello", 42]);
>fa2 : Symbol(fa2, Decl(typeParameterConstModifiers.ts, 151, 60))
declare function fb1<const T extends unknown[]>(...args: T): T;
>fb1 : Symbol(fb1, Decl(typeParameterConstModifiers.ts, 155, 19))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 157, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 157, 48))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 157, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 157, 21))
declare function fb2<const T extends readonly unknown[]>(...args: T): T;
>fb2 : Symbol(fb2, Decl(typeParameterConstModifiers.ts, 157, 63))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 158, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 158, 57))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 158, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 158, 21))
fb1("hello", 42);
>fb1 : Symbol(fb1, Decl(typeParameterConstModifiers.ts, 155, 19))
fb2("hello", 42);
>fb2 : Symbol(fb2, Decl(typeParameterConstModifiers.ts, 157, 63))
declare function fc1<const T extends unknown[]>(f: (...args: T) => void, ...args: T): T;
>fc1 : Symbol(fc1, Decl(typeParameterConstModifiers.ts, 161, 17))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 163, 21))
>f : Symbol(f, Decl(typeParameterConstModifiers.ts, 163, 48))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 163, 52))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 163, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 163, 72))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 163, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 163, 21))
declare function fc2<const T extends readonly unknown[]>(f: (...args: T) => void, ...args: T): T;
>fc2 : Symbol(fc2, Decl(typeParameterConstModifiers.ts, 163, 88))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 164, 21))
>f : Symbol(f, Decl(typeParameterConstModifiers.ts, 164, 57))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 164, 61))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 164, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 164, 81))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 164, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 164, 21))
fc1((a: string, b: number) => {}, "hello", 42);
>fc1 : Symbol(fc1, Decl(typeParameterConstModifiers.ts, 161, 17))
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 166, 5))
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 166, 15))
fc2((a: string, b: number) => {}, "hello", 42);
>fc2 : Symbol(fc2, Decl(typeParameterConstModifiers.ts, 163, 88))
>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 167, 5))
>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 167, 15))
declare function fd1<const T extends string[] | number[]>(args: T): T;
>fd1 : Symbol(fd1, Decl(typeParameterConstModifiers.ts, 167, 47))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 169, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 169, 58))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 169, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 169, 21))
declare function fd2<const T extends string[] | readonly number[]>(args: T): T;
>fd2 : Symbol(fd2, Decl(typeParameterConstModifiers.ts, 169, 70))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 170, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 170, 67))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 170, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 170, 21))
declare function fd3<const T extends readonly string[] | readonly number[]>(args: T): T;
>fd3 : Symbol(fd3, Decl(typeParameterConstModifiers.ts, 170, 79))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 171, 21))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 171, 76))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 171, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 171, 21))
fd1(["hello", "world"]);
>fd1 : Symbol(fd1, Decl(typeParameterConstModifiers.ts, 167, 47))
fd1([1, 2, 3]);
>fd1 : Symbol(fd1, Decl(typeParameterConstModifiers.ts, 167, 47))
fd2(["hello", "world"]);
>fd2 : Symbol(fd2, Decl(typeParameterConstModifiers.ts, 169, 70))
fd2([1, 2, 3]);
>fd2 : Symbol(fd2, Decl(typeParameterConstModifiers.ts, 169, 70))
fd3(["hello", "world"]);
>fd3 : Symbol(fd3, Decl(typeParameterConstModifiers.ts, 170, 79))
fd3([1, 2, 3]);
>fd3 : Symbol(fd3, Decl(typeParameterConstModifiers.ts, 170, 79))
declare function fn1<const T extends { foo: unknown[] }[]>(...args: T): T;
>fn1 : Symbol(fn1, Decl(typeParameterConstModifiers.ts, 178, 15))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 180, 21))
>foo : Symbol(foo, Decl(typeParameterConstModifiers.ts, 180, 38))
>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 180, 59))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 180, 21))
>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 180, 21))
fn1({ foo: ["hello", 123] }, { foo: [true]});
>fn1 : Symbol(fn1, Decl(typeParameterConstModifiers.ts, 178, 15))
>foo : Symbol(foo, Decl(typeParameterConstModifiers.ts, 182, 5))
>foo : Symbol(foo, Decl(typeParameterConstModifiers.ts, 182, 30))

View File

@@ -409,3 +409,302 @@ const tMapped = thingMapped({ foo: '' }); // { foo: "" }
>foo : ""
>'' : ""
// repro from https://github.com/microsoft/TypeScript/issues/55033
function factory_55033_minimal<const T extends readonly unknown[]>(cb: (...args: T) => void) {
>factory_55033_minimal : <const T extends readonly unknown[]>(cb: (...args: T) => void) => T
>cb : (...args: T) => void
>args : T
return {} as T
>{} as T : T
>{} : {}
}
const test_55033_minimal = factory_55033_minimal((b: string) => {})
>test_55033_minimal : readonly [b: string]
>factory_55033_minimal((b: string) => {}) : readonly [b: string]
>factory_55033_minimal : <const T extends readonly unknown[]>(cb: (...args: T) => void) => T
>(b: string) => {} : (b: string) => void
>b : string
function factory_55033<const T extends readonly unknown[]>(cb: (...args: T) => void) {
>factory_55033 : <const T extends readonly unknown[]>(cb: (...args: T) => void) => <const K extends T>(...args: K) => K
>cb : (...args: T) => void
>args : T
return function call<const K extends T>(...args: K): K {
>function call<const K extends T>(...args: K): K { return {} as K; } : <const K extends T>(...args: K) => K
>call : <const K extends T>(...args: K) => K
>args : K
return {} as K;
>{} as K : K
>{} : {}
};
}
const t1_55033 = factory_55033((a: { test: number }, b: string) => {})(
>t1_55033 : readonly [{ readonly test: 123; }, "some string"]
>factory_55033((a: { test: number }, b: string) => {})( { test: 123 }, "some string") : readonly [{ readonly test: 123; }, "some string"]
>factory_55033((a: { test: number }, b: string) => {}) : <const K extends readonly [a: { test: number; }, b: string]>(...args: K) => K
>factory_55033 : <const T extends readonly unknown[]>(cb: (...args: T) => void) => <const K extends T>(...args: K) => K
>(a: { test: number }, b: string) => {} : (a: { test: number;}, b: string) => void
>a : { test: number; }
>test : number
>b : string
{ test: 123 },
>{ test: 123 } : { test: 123; }
>test : 123
>123 : 123
"some string"
>"some string" : "some string"
);
const t2_55033 = factory_55033((a: { test: number }, b: string) => {})(
>t2_55033 : readonly [{ readonly test: 123; }, "some string"]
>factory_55033((a: { test: number }, b: string) => {})( { test: 123 } as const, "some string") : readonly [{ readonly test: 123; }, "some string"]
>factory_55033((a: { test: number }, b: string) => {}) : <const K extends readonly [a: { test: number; }, b: string]>(...args: K) => K
>factory_55033 : <const T extends readonly unknown[]>(cb: (...args: T) => void) => <const K extends T>(...args: K) => K
>(a: { test: number }, b: string) => {} : (a: { test: number;}, b: string) => void
>a : { test: number; }
>test : number
>b : string
{ test: 123 } as const,
>{ test: 123 } as const : { readonly test: 123; }
>{ test: 123 } : { readonly test: 123; }
>test : 123
>123 : 123
"some string"
>"some string" : "some string"
);
// Same with non-readonly constraint
function factory_55033_2<const T extends unknown[]>(cb: (...args: T) => void) {
>factory_55033_2 : <const T extends unknown[]>(cb: (...args: T) => void) => <const K extends T>(...args: K) => K
>cb : (...args: T) => void
>args : T
return function call<const K extends T>(...args: K): K {
>function call<const K extends T>(...args: K): K { return {} as K; } : <const K extends T>(...args: K) => K
>call : <const K extends T>(...args: K) => K
>args : K
return {} as K;
>{} as K : K
>{} : {}
};
}
const t1_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
>t1_55033_2 : [{ readonly test: 123; }, "some string"]
>factory_55033_2((a: { test: number }, b: string) => {})( { test: 123 }, "some string") : [{ readonly test: 123; }, "some string"]
>factory_55033_2((a: { test: number }, b: string) => {}) : <const K extends [a: { test: number; }, b: string]>(...args: K) => K
>factory_55033_2 : <const T extends unknown[]>(cb: (...args: T) => void) => <const K extends T>(...args: K) => K
>(a: { test: number }, b: string) => {} : (a: { test: number;}, b: string) => void
>a : { test: number; }
>test : number
>b : string
{ test: 123 },
>{ test: 123 } : { test: 123; }
>test : 123
>123 : 123
"some string"
>"some string" : "some string"
);
const t2_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
>t2_55033_2 : [{ readonly test: 123; }, "some string"]
>factory_55033_2((a: { test: number }, b: string) => {})( { test: 123 } as const, "some string") : [{ readonly test: 123; }, "some string"]
>factory_55033_2((a: { test: number }, b: string) => {}) : <const K extends [a: { test: number; }, b: string]>(...args: K) => K
>factory_55033_2 : <const T extends unknown[]>(cb: (...args: T) => void) => <const K extends T>(...args: K) => K
>(a: { test: number }, b: string) => {} : (a: { test: number;}, b: string) => void
>a : { test: number; }
>test : number
>b : string
{ test: 123 } as const,
>{ test: 123 } as const : { readonly test: 123; }
>{ test: 123 } : { readonly test: 123; }
>test : 123
>123 : 123
"some string"
>"some string" : "some string"
);
// Repro from https://github.com/microsoft/TypeScript/issues/51931
declare function fn<const T extends any[]>(...args: T): T;
>fn : <const T extends any[]>(...args: T) => T
>args : T
const a = fn("a", false);
>a : ["a", false]
>fn("a", false) : ["a", false]
>fn : <const T extends any[]>(...args: T) => T
>"a" : "a"
>false : false
// More examples of non-readonly constraints
declare function fa1<const T extends unknown[]>(args: T): T;
>fa1 : <const T extends unknown[]>(args: T) => T
>args : T
declare function fa2<const T extends readonly unknown[]>(args: T): T;
>fa2 : <const T extends readonly unknown[]>(args: T) => T
>args : T
fa1(["hello", 42]);
>fa1(["hello", 42]) : ["hello", 42]
>fa1 : <const T extends unknown[]>(args: T) => T
>["hello", 42] : ["hello", 42]
>"hello" : "hello"
>42 : 42
fa2(["hello", 42]);
>fa2(["hello", 42]) : readonly ["hello", 42]
>fa2 : <const T extends readonly unknown[]>(args: T) => T
>["hello", 42] : ["hello", 42]
>"hello" : "hello"
>42 : 42
declare function fb1<const T extends unknown[]>(...args: T): T;
>fb1 : <const T extends unknown[]>(...args: T) => T
>args : T
declare function fb2<const T extends readonly unknown[]>(...args: T): T;
>fb2 : <const T extends readonly unknown[]>(...args: T) => T
>args : T
fb1("hello", 42);
>fb1("hello", 42) : ["hello", 42]
>fb1 : <const T extends unknown[]>(...args: T) => T
>"hello" : "hello"
>42 : 42
fb2("hello", 42);
>fb2("hello", 42) : readonly ["hello", 42]
>fb2 : <const T extends readonly unknown[]>(...args: T) => T
>"hello" : "hello"
>42 : 42
declare function fc1<const T extends unknown[]>(f: (...args: T) => void, ...args: T): T;
>fc1 : <const T extends unknown[]>(f: (...args: T) => void, ...args: T) => T
>f : (...args: T) => void
>args : T
>args : T
declare function fc2<const T extends readonly unknown[]>(f: (...args: T) => void, ...args: T): T;
>fc2 : <const T extends readonly unknown[]>(f: (...args: T) => void, ...args: T) => T
>f : (...args: T) => void
>args : T
>args : T
fc1((a: string, b: number) => {}, "hello", 42);
>fc1((a: string, b: number) => {}, "hello", 42) : ["hello", 42]
>fc1 : <const T extends unknown[]>(f: (...args: T) => void, ...args: T) => T
>(a: string, b: number) => {} : (a: string, b: number) => void
>a : string
>b : number
>"hello" : "hello"
>42 : 42
fc2((a: string, b: number) => {}, "hello", 42);
>fc2((a: string, b: number) => {}, "hello", 42) : readonly ["hello", 42]
>fc2 : <const T extends readonly unknown[]>(f: (...args: T) => void, ...args: T) => T
>(a: string, b: number) => {} : (a: string, b: number) => void
>a : string
>b : number
>"hello" : "hello"
>42 : 42
declare function fd1<const T extends string[] | number[]>(args: T): T;
>fd1 : <const T extends string[] | number[]>(args: T) => T
>args : T
declare function fd2<const T extends string[] | readonly number[]>(args: T): T;
>fd2 : <const T extends string[] | readonly number[]>(args: T) => T
>args : T
declare function fd3<const T extends readonly string[] | readonly number[]>(args: T): T;
>fd3 : <const T extends readonly string[] | readonly number[]>(args: T) => T
>args : T
fd1(["hello", "world"]);
>fd1(["hello", "world"]) : ["hello", "world"]
>fd1 : <const T extends string[] | number[]>(args: T) => T
>["hello", "world"] : ["hello", "world"]
>"hello" : "hello"
>"world" : "world"
fd1([1, 2, 3]);
>fd1([1, 2, 3]) : [1, 2, 3]
>fd1 : <const T extends string[] | number[]>(args: T) => T
>[1, 2, 3] : [1, 2, 3]
>1 : 1
>2 : 2
>3 : 3
fd2(["hello", "world"]);
>fd2(["hello", "world"]) : ["hello", "world"]
>fd2 : <const T extends string[] | readonly number[]>(args: T) => T
>["hello", "world"] : ["hello", "world"]
>"hello" : "hello"
>"world" : "world"
fd2([1, 2, 3]);
>fd2([1, 2, 3]) : [1, 2, 3]
>fd2 : <const T extends string[] | readonly number[]>(args: T) => T
>[1, 2, 3] : [1, 2, 3]
>1 : 1
>2 : 2
>3 : 3
fd3(["hello", "world"]);
>fd3(["hello", "world"]) : readonly ["hello", "world"]
>fd3 : <const T extends readonly string[] | readonly number[]>(args: T) => T
>["hello", "world"] : ["hello", "world"]
>"hello" : "hello"
>"world" : "world"
fd3([1, 2, 3]);
>fd3([1, 2, 3]) : readonly [1, 2, 3]
>fd3 : <const T extends readonly string[] | readonly number[]>(args: T) => T
>[1, 2, 3] : [1, 2, 3]
>1 : 1
>2 : 2
>3 : 3
declare function fn1<const T extends { foo: unknown[] }[]>(...args: T): T;
>fn1 : <const T extends { foo: unknown[]; }[]>(...args: T) => T
>foo : unknown[]
>args : T
fn1({ foo: ["hello", 123] }, { foo: [true]});
>fn1({ foo: ["hello", 123] }, { foo: [true]}) : [{ readonly foo: ["hello", 123]; }, { readonly foo: [true]; }]
>fn1 : <const T extends { foo: unknown[]; }[]>(...args: T) => T
>{ foo: ["hello", 123] } : { foo: ["hello", 123]; }
>foo : ["hello", 123]
>["hello", 123] : ["hello", 123]
>"hello" : "hello"
>123 : 123
>{ foo: [true]} : { foo: [true]; }
>foo : [true]
>[true] : [true]
>true : true

View File

@@ -100,3 +100,86 @@ type NotEmptyMapped<T extends Record<string, any>> = keyof T extends never ? nev
const thingMapped = <const O extends Record<string, any>>(o: NotEmptyMapped<O>) => o;
const tMapped = thingMapped({ foo: '' }); // { foo: "" }
// repro from https://github.com/microsoft/TypeScript/issues/55033
function factory_55033_minimal<const T extends readonly unknown[]>(cb: (...args: T) => void) {
return {} as T
}
const test_55033_minimal = factory_55033_minimal((b: string) => {})
function factory_55033<const T extends readonly unknown[]>(cb: (...args: T) => void) {
return function call<const K extends T>(...args: K): K {
return {} as K;
};
}
const t1_55033 = factory_55033((a: { test: number }, b: string) => {})(
{ test: 123 },
"some string"
);
const t2_55033 = factory_55033((a: { test: number }, b: string) => {})(
{ test: 123 } as const,
"some string"
);
// Same with non-readonly constraint
function factory_55033_2<const T extends unknown[]>(cb: (...args: T) => void) {
return function call<const K extends T>(...args: K): K {
return {} as K;
};
}
const t1_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
{ test: 123 },
"some string"
);
const t2_55033_2 = factory_55033_2((a: { test: number }, b: string) => {})(
{ test: 123 } as const,
"some string"
);
// Repro from https://github.com/microsoft/TypeScript/issues/51931
declare function fn<const T extends any[]>(...args: T): T;
const a = fn("a", false);
// More examples of non-readonly constraints
declare function fa1<const T extends unknown[]>(args: T): T;
declare function fa2<const T extends readonly unknown[]>(args: T): T;
fa1(["hello", 42]);
fa2(["hello", 42]);
declare function fb1<const T extends unknown[]>(...args: T): T;
declare function fb2<const T extends readonly unknown[]>(...args: T): T;
fb1("hello", 42);
fb2("hello", 42);
declare function fc1<const T extends unknown[]>(f: (...args: T) => void, ...args: T): T;
declare function fc2<const T extends readonly unknown[]>(f: (...args: T) => void, ...args: T): T;
fc1((a: string, b: number) => {}, "hello", 42);
fc2((a: string, b: number) => {}, "hello", 42);
declare function fd1<const T extends string[] | number[]>(args: T): T;
declare function fd2<const T extends string[] | readonly number[]>(args: T): T;
declare function fd3<const T extends readonly string[] | readonly number[]>(args: T): T;
fd1(["hello", "world"]);
fd1([1, 2, 3]);
fd2(["hello", "world"]);
fd2([1, 2, 3]);
fd3(["hello", "world"]);
fd3([1, 2, 3]);
declare function fn1<const T extends { foo: unknown[] }[]>(...args: T): T;
fn1({ foo: ["hello", 123] }, { foo: [true]});