diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 73a15fd578777..b37d9c0a5db8b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -23265,6 +23265,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 + 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; @@ -23925,7 +23931,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); } } @@ -30045,7 +30051,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 ? getUnionType(sameMap(elementTypes, (t, i) => elementFlags[i] & ElementFlags.Variadic ? getIndexedAccessTypeOrUndefined(t, numberType) || anyType : t), UnionReduction.Subtype) : @@ -32623,7 +32629,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 { @@ -34928,7 +34934,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); @@ -34952,7 +34958,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 diff --git a/tests/baselines/reference/typeParameterConstModifiers.errors.txt b/tests/baselines/reference/typeParameterConstModifiers.errors.txt index 8a57e4b939313..3818707f74751 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.errors.txt +++ b/tests/baselines/reference/typeParameterConstModifiers.errors.txt @@ -107,4 +107,87 @@ typeParameterConstModifiers.ts(55,9): error TS1277: 'const' modifier can only ap const thingMapped = >(o: NotEmptyMapped) => o; const tMapped = thingMapped({ foo: '' }); // { foo: "" } + + // repro from https://github.com/microsoft/TypeScript/issues/55033 + + function factory_55033_minimal(cb: (...args: T) => void) { + return {} as T + } + + const test_55033_minimal = factory_55033_minimal((b: string) => {}) + + function factory_55033(cb: (...args: T) => void) { + return function call(...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(cb: (...args: T) => void) { + return function call(...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(...args: T): T; + + const a = fn("a", false); + + // More examples of non-readonly constraints + + declare function fa1(args: T): T; + declare function fa2(args: T): T; + + fa1(["hello", 42]); + fa2(["hello", 42]); + + declare function fb1(...args: T): T; + declare function fb2(...args: T): T; + + fb1("hello", 42); + fb2("hello", 42); + + declare function fc1(f: (...args: T) => void, ...args: T): T; + declare function fc2(f: (...args: T) => void, ...args: T): T; + + fc1((a: string, b: number) => {}, "hello", 42); + fc2((a: string, b: number) => {}, "hello", 42); + + declare function fd1(args: T): T; + declare function fd2(args: T): T; + declare function fd3(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(...args: T): T; + + fn1({ foo: ["hello", 123] }, { foo: [true]}); \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterConstModifiers.js b/tests/baselines/reference/typeParameterConstModifiers.js index 3fe57ad97a0e4..9c82ade3c5549 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.js +++ b/tests/baselines/reference/typeParameterConstModifiers.js @@ -101,6 +101,89 @@ type NotEmptyMapped> = keyof T extends never ? nev const thingMapped = >(o: NotEmptyMapped) => o; const tMapped = thingMapped({ foo: '' }); // { foo: "" } + +// repro from https://github.com/microsoft/TypeScript/issues/55033 + +function factory_55033_minimal(cb: (...args: T) => void) { + return {} as T +} + +const test_55033_minimal = factory_55033_minimal((b: string) => {}) + +function factory_55033(cb: (...args: T) => void) { + return function call(...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(cb: (...args: T) => void) { + return function call(...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(...args: T): T; + +const a = fn("a", false); + +// More examples of non-readonly constraints + +declare function fa1(args: T): T; +declare function fa2(args: T): T; + +fa1(["hello", 42]); +fa2(["hello", 42]); + +declare function fb1(...args: T): T; +declare function fb2(...args: T): T; + +fb1("hello", 42); +fb2("hello", 42); + +declare function fc1(f: (...args: T) => void, ...args: T): T; +declare function fc2(f: (...args: T) => void, ...args: T): T; + +fc1((a: string, b: number) => {}, "hello", 42); +fc2((a: string, b: number) => {}, "hello", 42); + +declare function fd1(args: T): T; +declare function fd2(args: T): T; +declare function fd3(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(...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] }); diff --git a/tests/baselines/reference/typeParameterConstModifiers.symbols b/tests/baselines/reference/typeParameterConstModifiers.symbols index 2ec51bed100f0..029008e299870 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.symbols +++ b/tests/baselines/reference/typeParameterConstModifiers.symbols @@ -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(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(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(...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(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(...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(...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(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(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(...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(...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(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(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(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(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(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(...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)) + diff --git a/tests/baselines/reference/typeParameterConstModifiers.types b/tests/baselines/reference/typeParameterConstModifiers.types index 809a64ce0b70c..5f7e230e14a25 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.types +++ b/tests/baselines/reference/typeParameterConstModifiers.types @@ -409,3 +409,302 @@ const tMapped = thingMapped({ foo: '' }); // { foo: "" } >foo : "" >'' : "" +// repro from https://github.com/microsoft/TypeScript/issues/55033 + +function factory_55033_minimal(cb: (...args: T) => void) { +>factory_55033_minimal : (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 : (cb: (...args: T) => void) => T +>(b: string) => {} : (b: string) => void +>b : string + +function factory_55033(cb: (...args: T) => void) { +>factory_55033 : (cb: (...args: T) => void) => (...args: K) => K +>cb : (...args: T) => void +>args : T + + return function call(...args: K): K { +>function call(...args: K): K { return {} as K; } : (...args: K) => K +>call : (...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) => {}) : (...args: K) => K +>factory_55033 : (cb: (...args: T) => void) => (...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) => {}) : (...args: K) => K +>factory_55033 : (cb: (...args: T) => void) => (...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(cb: (...args: T) => void) { +>factory_55033_2 : (cb: (...args: T) => void) => (...args: K) => K +>cb : (...args: T) => void +>args : T + + return function call(...args: K): K { +>function call(...args: K): K { return {} as K; } : (...args: K) => K +>call : (...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) => {}) : (...args: K) => K +>factory_55033_2 : (cb: (...args: T) => void) => (...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) => {}) : (...args: K) => K +>factory_55033_2 : (cb: (...args: T) => void) => (...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(...args: T): T; +>fn : (...args: T) => T +>args : T + +const a = fn("a", false); +>a : ["a", false] +>fn("a", false) : ["a", false] +>fn : (...args: T) => T +>"a" : "a" +>false : false + +// More examples of non-readonly constraints + +declare function fa1(args: T): T; +>fa1 : (args: T) => T +>args : T + +declare function fa2(args: T): T; +>fa2 : (args: T) => T +>args : T + +fa1(["hello", 42]); +>fa1(["hello", 42]) : ["hello", 42] +>fa1 : (args: T) => T +>["hello", 42] : ["hello", 42] +>"hello" : "hello" +>42 : 42 + +fa2(["hello", 42]); +>fa2(["hello", 42]) : readonly ["hello", 42] +>fa2 : (args: T) => T +>["hello", 42] : ["hello", 42] +>"hello" : "hello" +>42 : 42 + +declare function fb1(...args: T): T; +>fb1 : (...args: T) => T +>args : T + +declare function fb2(...args: T): T; +>fb2 : (...args: T) => T +>args : T + +fb1("hello", 42); +>fb1("hello", 42) : ["hello", 42] +>fb1 : (...args: T) => T +>"hello" : "hello" +>42 : 42 + +fb2("hello", 42); +>fb2("hello", 42) : readonly ["hello", 42] +>fb2 : (...args: T) => T +>"hello" : "hello" +>42 : 42 + +declare function fc1(f: (...args: T) => void, ...args: T): T; +>fc1 : (f: (...args: T) => void, ...args: T) => T +>f : (...args: T) => void +>args : T +>args : T + +declare function fc2(f: (...args: T) => void, ...args: T): T; +>fc2 : (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 : (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 : (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(args: T): T; +>fd1 : (args: T) => T +>args : T + +declare function fd2(args: T): T; +>fd2 : (args: T) => T +>args : T + +declare function fd3(args: T): T; +>fd3 : (args: T) => T +>args : T + +fd1(["hello", "world"]); +>fd1(["hello", "world"]) : ["hello", "world"] +>fd1 : (args: T) => T +>["hello", "world"] : ["hello", "world"] +>"hello" : "hello" +>"world" : "world" + +fd1([1, 2, 3]); +>fd1([1, 2, 3]) : [1, 2, 3] +>fd1 : (args: T) => T +>[1, 2, 3] : [1, 2, 3] +>1 : 1 +>2 : 2 +>3 : 3 + +fd2(["hello", "world"]); +>fd2(["hello", "world"]) : ["hello", "world"] +>fd2 : (args: T) => T +>["hello", "world"] : ["hello", "world"] +>"hello" : "hello" +>"world" : "world" + +fd2([1, 2, 3]); +>fd2([1, 2, 3]) : [1, 2, 3] +>fd2 : (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 : (args: T) => T +>["hello", "world"] : ["hello", "world"] +>"hello" : "hello" +>"world" : "world" + +fd3([1, 2, 3]); +>fd3([1, 2, 3]) : readonly [1, 2, 3] +>fd3 : (args: T) => T +>[1, 2, 3] : [1, 2, 3] +>1 : 1 +>2 : 2 +>3 : 3 + +declare function fn1(...args: T): T; +>fn1 : (...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 : (...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 + diff --git a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts index b66b92ff7024b..14afe2219d188 100644 --- a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts +++ b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts @@ -100,3 +100,86 @@ type NotEmptyMapped> = keyof T extends never ? nev const thingMapped = >(o: NotEmptyMapped) => o; const tMapped = thingMapped({ foo: '' }); // { foo: "" } + +// repro from https://github.com/microsoft/TypeScript/issues/55033 + +function factory_55033_minimal(cb: (...args: T) => void) { + return {} as T +} + +const test_55033_minimal = factory_55033_minimal((b: string) => {}) + +function factory_55033(cb: (...args: T) => void) { + return function call(...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(cb: (...args: T) => void) { + return function call(...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(...args: T): T; + +const a = fn("a", false); + +// More examples of non-readonly constraints + +declare function fa1(args: T): T; +declare function fa2(args: T): T; + +fa1(["hello", 42]); +fa2(["hello", 42]); + +declare function fb1(...args: T): T; +declare function fb2(...args: T): T; + +fb1("hello", 42); +fb2("hello", 42); + +declare function fc1(f: (...args: T) => void, ...args: T): T; +declare function fc2(f: (...args: T) => void, ...args: T): T; + +fc1((a: string, b: number) => {}, "hello", 42); +fc2((a: string, b: number) => {}, "hello", 42); + +declare function fd1(args: T): T; +declare function fd2(args: T): T; +declare function fd3(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(...args: T): T; + +fn1({ foo: ["hello", 123] }, { foo: [true]});