diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 645bf049f4e12..16e49c3017195 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10950,11 +10950,16 @@ namespace ts { isInJSFile(signature.declaration)); } + function getErasedConstraint(type: Type, typeParameters: readonly TypeParameter[]): Type | undefined { + const constraint = getConstraintOfType(type); + return constraint && contains(typeParameters, constraint) ? getErasedConstraint(constraint, typeParameters) : constraint; + } + function getBaseSignature(signature: Signature) { const typeParameters = signature.typeParameters; if (typeParameters) { const typeEraser = createTypeEraser(typeParameters); - const baseConstraints = map(typeParameters, tp => instantiateType(getBaseConstraintOfType(tp), typeEraser) || unknownType); + const baseConstraints = map(typeParameters, tp => instantiateType(getErasedConstraint(tp, typeParameters), typeEraser) || unknownType); return instantiateSignature(signature, createTypeMapper(typeParameters, baseConstraints), /*eraseTypeParameters*/ true); } return signature; @@ -14710,7 +14715,7 @@ namespace ts { // with respect to T. const sourceSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(sourceType)); const targetSig = checkMode & SignatureCheckMode.Callback ? undefined : getSingleCallSignature(getNonNullableType(targetType)); - const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && + const callbacks = sourceSig && targetSig && (getFalsyFlags(sourceType) & TypeFlags.Nullable) === (getFalsyFlags(targetType) & TypeFlags.Nullable); let related = callbacks ? compareSignaturesRelated(targetSig!, sourceSig!, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : @@ -14745,10 +14750,11 @@ namespace ts { // The following block preserves behavior forbidding boolean returning functions from being assignable to type guard returning functions const targetTypePredicate = getTypePredicateOfSignature(target); - if (targetTypePredicate) { - const sourceTypePredicate = getTypePredicateOfSignature(source); + const sourceTypePredicate = getTypePredicateOfSignature(source); + if (targetTypePredicate && (sourceTypePredicate || !(checkMode & SignatureCheckMode.BivariantCallback))) { if (sourceTypePredicate) { - result &= compareTypePredicateRelatedTo(sourceTypePredicate, targetTypePredicate, reportErrors, errorReporter, compareTypes); + result &= checkMode & SignatureCheckMode.BivariantCallback && compareTypePredicateRelatedTo(targetTypePredicate, sourceTypePredicate, /*reportErrors*/ false, /*errorReporter*/ undefined, compareTypes) || + compareTypePredicateRelatedTo(sourceTypePredicate, targetTypePredicate, reportErrors, errorReporter, compareTypes); } else if (isIdentifierTypePredicate(targetTypePredicate)) { if (reportErrors) { @@ -16566,34 +16572,33 @@ namespace ts { const saveErrorInfo = captureErrorCalculationState(); const incompatibleReporter = kind === SignatureKind.Construct ? reportIncompatibleConstructSignatureReturn : reportIncompatibleCallSignatureReturn; - if (getObjectFlags(source) & ObjectFlags.Instantiated && getObjectFlags(target) & ObjectFlags.Instantiated && source.symbol === target.symbol) { - // We have instantiations of the same anonymous type (which typically will be the type of a - // method). Simply do a pairwise comparison of the signatures in the two signature lists instead - // of the much more expensive N * M comparison matrix we explore below. We erase type parameters - // as they are known to always be the same. + const sameSignatureInstantiations = getObjectFlags(source) & ObjectFlags.Instantiated && getObjectFlags(target) & ObjectFlags.Instantiated && source.symbol === target.symbol; + if (sameSignatureInstantiations || sourceSignatures.length === 1 && targetSignatures.length === 1) { + // We have instantiations of the same anonymous type (which typically will be the type of a method) + // or we have non-overloaded signatures. Simply do a pairwise comparison of the signatures in the + // two signature lists instead of the much more expensive N * M comparison matrix we explore below. + const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks; for (let i = 0; i < targetSignatures.length; i++) { - const related = signatureRelatedTo(sourceSignatures[i], targetSignatures[i], /*erase*/ true, reportErrors, incompatibleReporter(sourceSignatures[i], targetSignatures[i])); + const s = sourceSignatures[i]; + const t = targetSignatures[i]; + // We erase type parameters for the comparable relation or when strict checks are disabled. + // Otherwise, when we have instantiations of the same anonymous type, we instantiate target + // type parameters to their constraints because the type parameters are known to be the same. + const effectiveSource = eraseGenerics ? getErasedSignature(s) : s; + const effectiveTarget = eraseGenerics ? getErasedSignature(t) : sameSignatureInstantiations ? getBaseSignature(t) : t; + const related = signatureRelatedTo(effectiveSource, effectiveTarget, reportErrors, incompatibleReporter(sourceSignatures[i], targetSignatures[i])); if (!related) { return Ternary.False; } result &= related; } } - else if (sourceSignatures.length === 1 && targetSignatures.length === 1) { - // For simple functions (functions with a single signature) we only erase type parameters for - // the comparable relation. Otherwise, if the source signature is generic, we instantiate it - // in the context of the target signature before checking the relationship. Ideally we'd do - // this regardless of the number of signatures, but the potential costs are prohibitive due - // to the quadratic nature of the logic below. - const eraseGenerics = relation === comparableRelation || !!compilerOptions.noStrictGenericChecks; - result = signatureRelatedTo(sourceSignatures[0], targetSignatures[0], eraseGenerics, reportErrors, incompatibleReporter(sourceSignatures[0], targetSignatures[0])); - } else { outer: for (const t of targetSignatures) { // Only elaborate errors from the first failure let shouldElaborateErrors = reportErrors; for (const s of sourceSignatures) { - const related = signatureRelatedTo(s, t, /*erase*/ true, shouldElaborateErrors, incompatibleReporter(s, t)); + const related = signatureRelatedTo(getErasedSignature(s), getErasedSignature(t), shouldElaborateErrors, incompatibleReporter(s, t)); if (related) { result &= related; resetErrorInfo(saveErrorInfo); @@ -16630,9 +16635,9 @@ namespace ts { /** * See signatureAssignableTo, compareSignaturesIdentical */ - function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary { - return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target, - relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedTo, reportUnreliableMarkers); + function signatureRelatedTo(source: Signature, target: Signature, reportErrors: boolean, incompatibleReporter: (source: Type, target: Type) => void): Ternary { + return compareSignaturesRelated(source, target, relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, + reportErrors, reportError, incompatibleReporter, isRelatedTo, reportUnreliableMarkers); } function signaturesIdenticalTo(source: Type, target: Type, kind: SignatureKind): Ternary { diff --git a/tests/baselines/reference/complexRecursiveCollections.types b/tests/baselines/reference/complexRecursiveCollections.types index feaff62048628..a9fc13e7d1dc1 100644 --- a/tests/baselines/reference/complexRecursiveCollections.types +++ b/tests/baselines/reference/complexRecursiveCollections.types @@ -1137,7 +1137,7 @@ declare module Immutable { >Seq : typeof Seq function isSeq(maybeSeq: any): maybeSeq is Seq.Indexed | Seq.Keyed; ->isSeq : (maybeSeq: any) => maybeSeq is Indexed | Keyed +>isSeq : (maybeSeq: any) => maybeSeq is Keyed | Indexed >maybeSeq : any >Seq : any >Seq : any diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt index b00409544decc..5e49aa37b6c82 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccess2.errors.txt @@ -26,9 +26,27 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(67,3): error TS232 tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(68,3): error TS2322: Type '123' is not assignable to type 'T[K]'. tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS2322: Type '123' is not assignable to type 'Type[K]'. Type '123' is not assignable to type 'never'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(126,1): error TS2322: Type 'Demo<{ b: string; }>' is not assignable to type 'Demo<{ a: number; }>'. + Types of parameters 'key' and 'key' are incompatible. + Type '"a"' is not assignable to type '"b"'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(127,1): error TS2322: Type 'Demo<{ a: number; b: string; }>' is not assignable to type 'Demo<{ a: number; }>'. + Property 'b' is missing in type '{ a: number; }' but required in type '{ a: number; b: string; }'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(128,1): error TS2322: Type 'Demo<{ a: number; }>' is not assignable to type 'Demo<{ b: string; }>'. + Types of parameters 'key' and 'key' are incompatible. + Type '"b"' is not assignable to type '"a"'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(129,1): error TS2322: Type 'Demo<{ a: number; b: string; }>' is not assignable to type 'Demo<{ b: string; }>'. + Property 'a' is missing in type '{ b: string; }' but required in type '{ a: number; b: string; }'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(130,1): error TS2322: Type 'Demo<{ a: number; }>' is not assignable to type 'Demo<{ a: number; b: string; }>'. + Types of parameters 'key' and 'key' are incompatible. + Type '"a" | "b"' is not assignable to type '"a"'. + Type '"b"' is not assignable to type '"a"'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(131,1): error TS2322: Type 'Demo<{ b: string; }>' is not assignable to type 'Demo<{ a: number; b: string; }>'. + Types of parameters 'key' and 'key' are incompatible. + Type '"a" | "b"' is not assignable to type '"b"'. + Type '"a"' is not assignable to type '"b"'. -==== tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts (23 errors) ==== +==== tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts (29 errors) ==== function f1(obj: { a: number, b: 0 | 1, c: string }, k0: 'a', k1: 'a' | 'b', k2: 'a' | 'b' | 'c') { obj[k0] = 1; obj[k0] = 2; @@ -197,6 +215,45 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23 type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; + // Repro from 31006 + + type Demo = (key: K, val: T[K]) => void; + + declare let da: Demo<{ a: number }>; + declare let db: Demo<{ b: string }>; + declare let dc: Demo<{ a: number, b: string }>; + + da = db; // Error + ~~ +!!! error TS2322: Type 'Demo<{ b: string; }>' is not assignable to type 'Demo<{ a: number; }>'. +!!! error TS2322: Types of parameters 'key' and 'key' are incompatible. +!!! error TS2322: Type '"a"' is not assignable to type '"b"'. + da = dc; + ~~ +!!! error TS2322: Type 'Demo<{ a: number; b: string; }>' is not assignable to type 'Demo<{ a: number; }>'. +!!! error TS2322: Property 'b' is missing in type '{ a: number; }' but required in type '{ a: number; b: string; }'. + db = da; // Error + ~~ +!!! error TS2322: Type 'Demo<{ a: number; }>' is not assignable to type 'Demo<{ b: string; }>'. +!!! error TS2322: Types of parameters 'key' and 'key' are incompatible. +!!! error TS2322: Type '"b"' is not assignable to type '"a"'. + db = dc; + ~~ +!!! error TS2322: Type 'Demo<{ a: number; b: string; }>' is not assignable to type 'Demo<{ b: string; }>'. +!!! error TS2322: Property 'a' is missing in type '{ b: string; }' but required in type '{ a: number; b: string; }'. + dc = da; // Error + ~~ +!!! error TS2322: Type 'Demo<{ a: number; }>' is not assignable to type 'Demo<{ a: number; b: string; }>'. +!!! error TS2322: Types of parameters 'key' and 'key' are incompatible. +!!! error TS2322: Type '"a" | "b"' is not assignable to type '"a"'. +!!! error TS2322: Type '"b"' is not assignable to type '"a"'. + dc = db; // Error + ~~ +!!! error TS2322: Type 'Demo<{ b: string; }>' is not assignable to type 'Demo<{ a: number; b: string; }>'. +!!! error TS2322: Types of parameters 'key' and 'key' are incompatible. +!!! error TS2322: Type '"a" | "b"' is not assignable to type '"b"'. +!!! error TS2322: Type '"a"' is not assignable to type '"b"'. + // Repros from #30938 function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.js b/tests/baselines/reference/keyofAndIndexedAccess2.js index a2d7f9b2fdde9..f1b72c815f0bd 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.js +++ b/tests/baselines/reference/keyofAndIndexedAccess2.js @@ -116,6 +116,21 @@ type StrictExclude = T extends StrictExtract ? never : T; type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; +// Repro from 31006 + +type Demo = (key: K, val: T[K]) => void; + +declare let da: Demo<{ a: number }>; +declare let db: Demo<{ b: string }>; +declare let dc: Demo<{ a: number, b: string }>; + +da = db; // Error +da = dc; +db = da; // Error +db = dc; +dc = da; // Error +dc = db; // Error + // Repros from #30938 function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { @@ -240,6 +255,12 @@ export function getEntity(id, state) { function get123() { return 123; // Error } +da = db; // Error +da = dc; +db = da; // Error +db = dc; +dc = da; // Error +dc = db; // Error // Repros from #30938 function fn(param, cb) { cb(param.elements[0]); diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.symbols b/tests/baselines/reference/keyofAndIndexedAccess2.symbols index 58b5f470c030b..2acf707c38da0 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.symbols +++ b/tests/baselines/reference/keyofAndIndexedAccess2.symbols @@ -434,156 +434,209 @@ type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; >Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 115, 20)) >V : Symbol(V, Decl(keyofAndIndexedAccess2.ts, 115, 9)) +// Repro from 31006 + +type Demo = (key: K, val: T[K]) => void; +>Demo : Symbol(Demo, Decl(keyofAndIndexedAccess2.ts, 115, 69)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 10)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 119, 16)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 10)) +>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 119, 35)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 119, 16)) +>val : Symbol(val, Decl(keyofAndIndexedAccess2.ts, 119, 42)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 10)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 119, 16)) + +declare let da: Demo<{ a: number }>; +>da : Symbol(da, Decl(keyofAndIndexedAccess2.ts, 121, 11)) +>Demo : Symbol(Demo, Decl(keyofAndIndexedAccess2.ts, 115, 69)) +>a : Symbol(a, Decl(keyofAndIndexedAccess2.ts, 121, 22)) + +declare let db: Demo<{ b: string }>; +>db : Symbol(db, Decl(keyofAndIndexedAccess2.ts, 122, 11)) +>Demo : Symbol(Demo, Decl(keyofAndIndexedAccess2.ts, 115, 69)) +>b : Symbol(b, Decl(keyofAndIndexedAccess2.ts, 122, 22)) + +declare let dc: Demo<{ a: number, b: string }>; +>dc : Symbol(dc, Decl(keyofAndIndexedAccess2.ts, 123, 11)) +>Demo : Symbol(Demo, Decl(keyofAndIndexedAccess2.ts, 115, 69)) +>a : Symbol(a, Decl(keyofAndIndexedAccess2.ts, 123, 22)) +>b : Symbol(b, Decl(keyofAndIndexedAccess2.ts, 123, 33)) + +da = db; // Error +>da : Symbol(da, Decl(keyofAndIndexedAccess2.ts, 121, 11)) +>db : Symbol(db, Decl(keyofAndIndexedAccess2.ts, 122, 11)) + +da = dc; +>da : Symbol(da, Decl(keyofAndIndexedAccess2.ts, 121, 11)) +>dc : Symbol(dc, Decl(keyofAndIndexedAccess2.ts, 123, 11)) + +db = da; // Error +>db : Symbol(db, Decl(keyofAndIndexedAccess2.ts, 122, 11)) +>da : Symbol(da, Decl(keyofAndIndexedAccess2.ts, 121, 11)) + +db = dc; +>db : Symbol(db, Decl(keyofAndIndexedAccess2.ts, 122, 11)) +>dc : Symbol(dc, Decl(keyofAndIndexedAccess2.ts, 123, 11)) + +dc = da; // Error +>dc : Symbol(dc, Decl(keyofAndIndexedAccess2.ts, 123, 11)) +>da : Symbol(da, Decl(keyofAndIndexedAccess2.ts, 121, 11)) + +dc = db; // Error +>dc : Symbol(dc, Decl(keyofAndIndexedAccess2.ts, 123, 11)) +>db : Symbol(db, Decl(keyofAndIndexedAccess2.ts, 122, 11)) + // Repros from #30938 function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { ->fn : Symbol(fn, Decl(keyofAndIndexedAccess2.ts, 115, 69)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12)) ->elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23)) +>fn : Symbol(fn, Decl(keyofAndIndexedAccess2.ts, 130, 8)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 134, 12)) +>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 134, 23)) >Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) ->elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 51)) +>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 134, 51)) >Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) ->param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 119, 77)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12)) ->cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 119, 86)) ->element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 119, 92)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 119, 12)) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 134, 77)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 134, 12)) +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 134, 86)) +>element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 134, 92)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 134, 12)) cb(param.elements[0]); ->cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 119, 86)) ->param.elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23), Decl(keyofAndIndexedAccess2.ts, 119, 51)) ->param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 119, 77)) ->elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 119, 23), Decl(keyofAndIndexedAccess2.ts, 119, 51)) +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 134, 86)) +>param.elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 134, 23), Decl(keyofAndIndexedAccess2.ts, 134, 51)) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 134, 77)) +>elements : Symbol(elements, Decl(keyofAndIndexedAccess2.ts, 134, 23), Decl(keyofAndIndexedAccess2.ts, 134, 51)) } function fn2>(param: T, cb: (element: T[number]) => void) { ->fn2 : Symbol(fn2, Decl(keyofAndIndexedAccess2.ts, 121, 1)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13)) +>fn2 : Symbol(fn2, Decl(keyofAndIndexedAccess2.ts, 136, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 138, 13)) >Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) ->param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 123, 38)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13)) ->cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 123, 47)) ->element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 123, 53)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 123, 13)) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 138, 38)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 138, 13)) +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 138, 47)) +>element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 138, 53)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 138, 13)) cb(param[0]); ->cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 123, 47)) ->param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 123, 38)) +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 138, 47)) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 138, 38)) } // Repro from #31149 function fn3>(param: T, cb: (element: T[number]) => void) { ->fn3 : Symbol(fn3, Decl(keyofAndIndexedAccess2.ts, 125, 1)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 129, 13)) +>fn3 : Symbol(fn3, Decl(keyofAndIndexedAccess2.ts, 140, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 144, 13)) >ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --), Decl(lib.es2019.array.d.ts, --, --)) ->param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 129, 46)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 129, 13)) ->cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 129, 55)) ->element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 129, 61)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 129, 13)) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 144, 46)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 144, 13)) +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 144, 55)) +>element : Symbol(element, Decl(keyofAndIndexedAccess2.ts, 144, 61)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 144, 13)) cb(param[0]); ->cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 129, 55)) ->param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 129, 46)) +>cb : Symbol(cb, Decl(keyofAndIndexedAccess2.ts, 144, 55)) +>param : Symbol(param, Decl(keyofAndIndexedAccess2.ts, 144, 46)) } function fn4() { ->fn4 : Symbol(fn4, Decl(keyofAndIndexedAccess2.ts, 131, 1)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 133, 13)) +>fn4 : Symbol(fn4, Decl(keyofAndIndexedAccess2.ts, 146, 1)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 148, 13)) let x: Array[K] = 'abc'; ->x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 134, 7)) +>x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 149, 7)) >Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 2 more) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 133, 13)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 148, 13)) let y: ReadonlyArray[K] = 'abc'; ->y : Symbol(y, Decl(keyofAndIndexedAccess2.ts, 135, 7)) +>y : Symbol(y, Decl(keyofAndIndexedAccess2.ts, 150, 7)) >ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --), Decl(lib.es2019.array.d.ts, --, --)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 133, 13)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 148, 13)) } // Repro from #31439 and #31691 export class c { ->c : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 136, 1)) +>c : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 151, 1)) [x: string]: string; ->x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 141, 3)) +>x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 156, 3)) constructor() { this.a = "b"; ->this : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 136, 1)) +>this : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 151, 1)) this["a"] = "b"; ->this : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 136, 1)) +>this : Symbol(c, Decl(keyofAndIndexedAccess2.ts, 151, 1)) } } // Repro from #31385 type Foo = { [key: string]: { [K in keyof T]: K }[keyof T] }; ->Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 146, 1)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 150, 9)) ->key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 150, 17)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 150, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 150, 9)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 150, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 150, 9)) +>Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 161, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 165, 9)) +>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 165, 17)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 165, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 165, 9)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 165, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 165, 9)) type Bar = { [key: string]: { [K in keyof T]: [K] }[keyof T] }; ->Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 150, 64)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 152, 9)) ->key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 152, 17)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 152, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 152, 9)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 152, 34)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 152, 9)) +>Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 165, 64)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 167, 9)) +>key : Symbol(key, Decl(keyofAndIndexedAccess2.ts, 167, 17)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 167, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 167, 9)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 167, 34)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 167, 9)) type Baz> = { [K in keyof Q]: T[Q[K]] }; ->Baz : Symbol(Baz, Decl(keyofAndIndexedAccess2.ts, 152, 66)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 154, 9)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 154, 11)) ->Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 146, 1)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 154, 9)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 154, 35)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 154, 11)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 154, 9)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 154, 11)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 154, 35)) +>Baz : Symbol(Baz, Decl(keyofAndIndexedAccess2.ts, 167, 66)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 169, 9)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 169, 11)) +>Foo : Symbol(Foo, Decl(keyofAndIndexedAccess2.ts, 161, 1)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 169, 9)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 169, 35)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 169, 11)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 169, 9)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 169, 11)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 169, 35)) type Qux> = { [K in keyof Q]: T[Q[K]["0"]] }; ->Qux : Symbol(Qux, Decl(keyofAndIndexedAccess2.ts, 154, 60)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 156, 9)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 156, 11)) ->Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 150, 64)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 156, 9)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 156, 35)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 156, 11)) ->T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 156, 9)) ->Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 156, 11)) ->K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 156, 35)) +>Qux : Symbol(Qux, Decl(keyofAndIndexedAccess2.ts, 169, 60)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 171, 9)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 171, 11)) +>Bar : Symbol(Bar, Decl(keyofAndIndexedAccess2.ts, 165, 64)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 171, 9)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 171, 35)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 171, 11)) +>T : Symbol(T, Decl(keyofAndIndexedAccess2.ts, 171, 9)) +>Q : Symbol(Q, Decl(keyofAndIndexedAccess2.ts, 171, 11)) +>K : Symbol(K, Decl(keyofAndIndexedAccess2.ts, 171, 35)) // Repro from #32038 const actions = ['resizeTo', 'resizeBy'] as const; ->actions : Symbol(actions, Decl(keyofAndIndexedAccess2.ts, 160, 5)) +>actions : Symbol(actions, Decl(keyofAndIndexedAccess2.ts, 175, 5)) for (const action of actions) { ->action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 161, 10)) ->actions : Symbol(actions, Decl(keyofAndIndexedAccess2.ts, 160, 5)) +>action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 176, 10)) +>actions : Symbol(actions, Decl(keyofAndIndexedAccess2.ts, 175, 5)) window[action] = (x, y) => { >window : Symbol(window, Decl(lib.dom.d.ts, --, --)) ->action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 161, 10)) ->x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 162, 19)) ->y : Symbol(y, Decl(keyofAndIndexedAccess2.ts, 162, 21)) +>action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 176, 10)) +>x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 177, 19)) +>y : Symbol(y, Decl(keyofAndIndexedAccess2.ts, 177, 21)) window[action](x, y); >window : Symbol(window, Decl(lib.dom.d.ts, --, --)) ->action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 161, 10)) ->x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 162, 19)) ->y : Symbol(y, Decl(keyofAndIndexedAccess2.ts, 162, 21)) +>action : Symbol(action, Decl(keyofAndIndexedAccess2.ts, 176, 10)) +>x : Symbol(x, Decl(keyofAndIndexedAccess2.ts, 177, 19)) +>y : Symbol(y, Decl(keyofAndIndexedAccess2.ts, 177, 21)) } } diff --git a/tests/baselines/reference/keyofAndIndexedAccess2.types b/tests/baselines/reference/keyofAndIndexedAccess2.types index 66766a2759532..8f314436bfb14 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess2.types +++ b/tests/baselines/reference/keyofAndIndexedAccess2.types @@ -437,6 +437,56 @@ type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; >B : A<{ [Q in keyof T]: StrictExclude, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }>, {}>; }> +// Repro from 31006 + +type Demo = (key: K, val: T[K]) => void; +>Demo : Demo +>key : K +>val : T[K] + +declare let da: Demo<{ a: number }>; +>da : Demo<{ a: number; }> +>a : number + +declare let db: Demo<{ b: string }>; +>db : Demo<{ b: string; }> +>b : string + +declare let dc: Demo<{ a: number, b: string }>; +>dc : Demo<{ a: number; b: string; }> +>a : number +>b : string + +da = db; // Error +>da = db : Demo<{ b: string; }> +>da : Demo<{ a: number; }> +>db : Demo<{ b: string; }> + +da = dc; +>da = dc : Demo<{ a: number; b: string; }> +>da : Demo<{ a: number; }> +>dc : Demo<{ a: number; b: string; }> + +db = da; // Error +>db = da : Demo<{ a: number; }> +>db : Demo<{ b: string; }> +>da : Demo<{ a: number; }> + +db = dc; +>db = dc : Demo<{ a: number; b: string; }> +>db : Demo<{ b: string; }> +>dc : Demo<{ a: number; b: string; }> + +dc = da; // Error +>dc = da : Demo<{ a: number; }> +>dc : Demo<{ a: number; b: string; }> +>da : Demo<{ a: number; }> + +dc = db; // Error +>dc = db : Demo<{ b: string; }> +>dc : Demo<{ a: number; b: string; }> +>db : Demo<{ b: string; }> + // Repros from #30938 function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) { diff --git a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts index a86f4718e35c7..f7e371deb1585 100644 --- a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts +++ b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts @@ -118,6 +118,21 @@ type StrictExclude = T extends StrictExtract ? never : T; type A = { [Q in { [P in keyof T]: P; }[keyof T]]: T[Q]; }; type B = A<{ [Q in keyof T]: StrictExclude, {}>; }>; +// Repro from 31006 + +type Demo = (key: K, val: T[K]) => void; + +declare let da: Demo<{ a: number }>; +declare let db: Demo<{ b: string }>; +declare let dc: Demo<{ a: number, b: string }>; + +da = db; // Error +da = dc; +db = da; // Error +db = dc; +dc = da; // Error +dc = db; // Error + // Repros from #30938 function fn} | {elements: Array}>(param: T, cb: (element: T['elements'][number]) => void) {