diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 78ff1efc867da..e9953728741c6 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7151,9 +7151,80 @@ namespace ts { stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String)); numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number)); } + callSignatures = intersectCallSignatures(callSignatures); setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); } + function callSignaturesAreIdenticalExceptReturnType(a: Signature, b: Signature): boolean { + const parametersA = a.parameters; + const parametersB = b.parameters; + + if (parametersA.length !== parametersB.length) { + return false; + } + + if (!every(parametersA, (parameter, i) => isTypeIdenticalTo(getTypeOfParameter(parameter), getTypeOfParameter(parametersB[i])))) { + return false; + } + + // Parameter types are identical, now check type parameters. + const typesA = a.typeParameters; + const typesB = b.typeParameters; + + if (typesA === undefined || typesB === undefined) { + return typesA === typesB; + } + + if (typesA.length !== typesB.length) { + return false; + } + + return every(typesA, (parameter, i) => { + const constraintA = getConstraintOfTypeParameter(parameter); + const constraintB = getConstraintOfTypeParameter(typesB[i]); + const sameConstraints = (constraintA === undefined && constraintB === undefined) || + (constraintA !== undefined && constraintB !== undefined && isTypeIdenticalTo(constraintA, constraintB)); + + const defaultA = parameter.default; + const defaultB = typesB[i].default; + const sameDefaults = (defaultA === undefined && defaultB === undefined) || + (defaultA !== undefined && defaultB !== undefined && isTypeIdenticalTo(defaultA, defaultB)); + + return sameConstraints && sameDefaults; + }); + } + + function intersectCallSignatures(callSignatures: ReadonlyArray): ReadonlyArray { + if (callSignatures.length === 0) { + return callSignatures; + } + + // Overloads that differ only by return type are not usable, so: + // 1. Group all the call signatures by their type parameters + parameter types. Each group is an overload. + // 2. Create a new signature for each group where the return type is the intersection + // of the return types of the signatures in that group. + const groups: Signature[][] = []; + + callSignatures.forEach((callSignature) => { + const matchingGroup = find(groups, (group) => callSignaturesAreIdenticalExceptReturnType(callSignature, group[0])); + if (matchingGroup === undefined) { + groups.push([callSignature]); + } + else { + matchingGroup.push(callSignature); + } + }); + + return groups.map((signatures) => { + if (signatures.length === 1) { + return signatures[0]; + } + const clone = cloneSignature(signatures[0]); + clone.resolvedReturnType = getIntersectionType(signatures.map(signature => getReturnTypeOfSignature(signature))); + return clone; + }); + } + /** * Converts an AnonymousType to a ResolvedType. */ diff --git a/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt index 36ebc70b76ce3..d5bd047ffe41e 100644 --- a/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt +++ b/tests/baselines/reference/checkJsxGenericTagHasCorrectInferences.errors.txt @@ -1,6 +1,5 @@ -tests/cases/conformance/jsx/file.tsx(13,54): error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '((a: { x: string; }) => string) & ((cur: { x: string; }) => { x: string; })'. - Type '(a: { x: string; }) => string' is not assignable to type '(cur: { x: string; }) => { x: string; }'. - Type 'string' is not assignable to type '{ x: string; }'. +tests/cases/conformance/jsx/file.tsx(13,71): error TS2322: Type 'string' is not assignable to type 'string & { x: string; }'. + Type 'string' is not assignable to type '{ x: string; }'. ==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== @@ -17,8 +16,6 @@ tests/cases/conformance/jsx/file.tsx(13,54): error TS2322: Type '(a: { x: string let b = a} />; // No error - Values should be reinstantiated with `number` (since `object` is a default, not a constraint) let c = ({ x: a.x })} />; // No Error let d = a.x} />; // Error - `string` is not assignable to `{x: string}` - ~~~~~~~~~~ -!!! error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '((a: { x: string; }) => string) & ((cur: { x: string; }) => { x: string; })'. -!!! error TS2322: Type '(a: { x: string; }) => string' is not assignable to type '(cur: { x: string; }) => { x: string; }'. -!!! error TS2322: Type 'string' is not assignable to type '{ x: string; }'. -!!! related TS6500 tests/cases/conformance/jsx/file.tsx:13:54: The expected type comes from property 'nextValues' which is declared here on type 'IntrinsicAttributes & IntrinsicClassAttributes string; }, { x: string; }>> & { initialValues: { x: string; }; nextValues: (a: { x: string; }) => string; } & BaseProps<{ x: string; }> & { children?: ReactNode; }' \ No newline at end of file + ~~~ +!!! error TS2322: Type 'string' is not assignable to type 'string & { x: string; }'. +!!! error TS2322: Type 'string' is not assignable to type '{ x: string; }'. \ No newline at end of file diff --git a/tests/baselines/reference/intersectionOfCallsWithSameParameters.errors.txt b/tests/baselines/reference/intersectionOfCallsWithSameParameters.errors.txt new file mode 100644 index 0000000000000..f33695ffd3852 --- /dev/null +++ b/tests/baselines/reference/intersectionOfCallsWithSameParameters.errors.txt @@ -0,0 +1,61 @@ +tests/cases/compiler/intersectionOfCallsWithSameParameters.ts(38,7): error TS2741: Property 'two' is missing in type '{ one: number; }' but required in type '{ one: number; two: number; }'. +tests/cases/compiler/intersectionOfCallsWithSameParameters.ts(39,7): error TS2741: Property 'two' is missing in type '{ one: number; }' but required in type '{ one: number; two: number; }'. +tests/cases/compiler/intersectionOfCallsWithSameParameters.ts(40,7): error TS2741: Property 'two' is missing in type '{ one: number; }' but required in type '{ one: number; two: number; }'. +tests/cases/compiler/intersectionOfCallsWithSameParameters.ts(41,7): error TS2741: Property 'two' is missing in type '{ one: number; }' but required in type '{ one: number; two: number; }'. + + +==== tests/cases/compiler/intersectionOfCallsWithSameParameters.ts (4 errors) ==== + interface One { + differentParameterType(id: string): { one: number }; + differentNumberOfParameters(id: string): { one: number }; + differentTypeParameterDefault(id: string): { one: number }; + differentTypeParameterConstraint(id: string): { one: number }; + + same1(id: string): { one: number }; + same2(id: string): { one: number }; + same3(id: string): { one: number }; + same4(id: string): { one: number }; + same5(id: string): { one: number }; + } + + interface Two { + differentParameterType(id: number): { two: number }; + differentNumberOfParameters(id: string, second: string): { two: number }; + differentTypeParameterDefault(id: string): { two: number }; + differentTypeParameterConstraint(id: string): { two: number }; + + same1(id: string): { two: number }; + same2(id: string): { two: number }; + same3(id: string): { two: number }; + same4(id: string): { two: number }; + same5(id: string): { two: number }; + } + + const i: One & Two = {}; + + // These lines should type check; the return type should be intersected. + const same1: { one: number, two: number } = i.same1('test'); + const same2: { one: number, two: number } = i.same2('test'); + const same3: { one: number, two: number } = i.same3<{ one:number }>('test'); + const same4: { one: number, two: number } = i.same4('test'); + const same5: { one: number, two: number } = i.same5<{ one:number }, string>('test'); + + // These lines should not, because the functions should become overloads rather + // than the return types intersected. + const differentParameterType: { one: number, two: number } = i.differentParameterType('test'); + ~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2741: Property 'two' is missing in type '{ one: number; }' but required in type '{ one: number; two: number; }'. +!!! related TS2728 tests/cases/compiler/intersectionOfCallsWithSameParameters.ts:38:46: 'two' is declared here. + const differentNumberOfParameters: { one: number, two: number } = i.differentNumberOfParameters('test'); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2741: Property 'two' is missing in type '{ one: number; }' but required in type '{ one: number; two: number; }'. +!!! related TS2728 tests/cases/compiler/intersectionOfCallsWithSameParameters.ts:39:51: 'two' is declared here. + const differentTypeParameterDefault: { one: number, two: number } = i.differentTypeParameterDefault('test'); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2741: Property 'two' is missing in type '{ one: number; }' but required in type '{ one: number; two: number; }'. +!!! related TS2728 tests/cases/compiler/intersectionOfCallsWithSameParameters.ts:40:53: 'two' is declared here. + const differentTypeParameterConstraint: { one: number, two: number } = i.differentTypeParameterConstraint<{ one: number }>('test'); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2741: Property 'two' is missing in type '{ one: number; }' but required in type '{ one: number; two: number; }'. +!!! related TS2728 tests/cases/compiler/intersectionOfCallsWithSameParameters.ts:41:56: 'two' is declared here. + \ No newline at end of file diff --git a/tests/baselines/reference/intersectionOfCallsWithSameParameters.js b/tests/baselines/reference/intersectionOfCallsWithSameParameters.js new file mode 100644 index 0000000000000..e2c82c0f7d1c3 --- /dev/null +++ b/tests/baselines/reference/intersectionOfCallsWithSameParameters.js @@ -0,0 +1,59 @@ +//// [intersectionOfCallsWithSameParameters.ts] +interface One { + differentParameterType(id: string): { one: number }; + differentNumberOfParameters(id: string): { one: number }; + differentTypeParameterDefault(id: string): { one: number }; + differentTypeParameterConstraint(id: string): { one: number }; + + same1(id: string): { one: number }; + same2(id: string): { one: number }; + same3(id: string): { one: number }; + same4(id: string): { one: number }; + same5(id: string): { one: number }; +} + +interface Two { + differentParameterType(id: number): { two: number }; + differentNumberOfParameters(id: string, second: string): { two: number }; + differentTypeParameterDefault(id: string): { two: number }; + differentTypeParameterConstraint(id: string): { two: number }; + + same1(id: string): { two: number }; + same2(id: string): { two: number }; + same3(id: string): { two: number }; + same4(id: string): { two: number }; + same5(id: string): { two: number }; +} + +const i: One & Two = {}; + +// These lines should type check; the return type should be intersected. +const same1: { one: number, two: number } = i.same1('test'); +const same2: { one: number, two: number } = i.same2('test'); +const same3: { one: number, two: number } = i.same3<{ one:number }>('test'); +const same4: { one: number, two: number } = i.same4('test'); +const same5: { one: number, two: number } = i.same5<{ one:number }, string>('test'); + +// These lines should not, because the functions should become overloads rather +// than the return types intersected. +const differentParameterType: { one: number, two: number } = i.differentParameterType('test'); +const differentNumberOfParameters: { one: number, two: number } = i.differentNumberOfParameters('test'); +const differentTypeParameterDefault: { one: number, two: number } = i.differentTypeParameterDefault('test'); +const differentTypeParameterConstraint: { one: number, two: number } = i.differentTypeParameterConstraint<{ one: number }>('test'); + + +//// [intersectionOfCallsWithSameParameters.js] +"use strict"; +var i = {}; +// These lines should type check; the return type should be intersected. +var same1 = i.same1('test'); +var same2 = i.same2('test'); +var same3 = i.same3('test'); +var same4 = i.same4('test'); +var same5 = i.same5('test'); +// These lines should not, because the functions should become overloads rather +// than the return types intersected. +var differentParameterType = i.differentParameterType('test'); +var differentNumberOfParameters = i.differentNumberOfParameters('test'); +var differentTypeParameterDefault = i.differentTypeParameterDefault('test'); +var differentTypeParameterConstraint = i.differentTypeParameterConstraint('test'); diff --git a/tests/baselines/reference/intersectionOfCallsWithSameParameters.symbols b/tests/baselines/reference/intersectionOfCallsWithSameParameters.symbols new file mode 100644 index 0000000000000..9afd35400564b --- /dev/null +++ b/tests/baselines/reference/intersectionOfCallsWithSameParameters.symbols @@ -0,0 +1,203 @@ +=== tests/cases/compiler/intersectionOfCallsWithSameParameters.ts === +interface One { +>One : Symbol(One, Decl(intersectionOfCallsWithSameParameters.ts, 0, 0)) + + differentParameterType(id: string): { one: number }; +>differentParameterType : Symbol(One.differentParameterType, Decl(intersectionOfCallsWithSameParameters.ts, 0, 15)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 1, 27)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 1, 41)) + + differentNumberOfParameters(id: string): { one: number }; +>differentNumberOfParameters : Symbol(One.differentNumberOfParameters, Decl(intersectionOfCallsWithSameParameters.ts, 1, 56)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 2, 32)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 2, 46)) + + differentTypeParameterDefault(id: string): { one: number }; +>differentTypeParameterDefault : Symbol(One.differentTypeParameterDefault, Decl(intersectionOfCallsWithSameParameters.ts, 2, 61)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 3, 34)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 3, 46)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 3, 60)) + + differentTypeParameterConstraint(id: string): { one: number }; +>differentTypeParameterConstraint : Symbol(One.differentTypeParameterConstraint, Decl(intersectionOfCallsWithSameParameters.ts, 3, 75)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 4, 37)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 4, 48)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 4, 64)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 4, 78)) + + same1(id: string): { one: number }; +>same1 : Symbol(One.same1, Decl(intersectionOfCallsWithSameParameters.ts, 4, 93)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 6, 10)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 6, 24)) + + same2(id: string): { one: number }; +>same2 : Symbol(One.same2, Decl(intersectionOfCallsWithSameParameters.ts, 6, 39)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 7, 10)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 7, 13)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 7, 27)) + + same3(id: string): { one: number }; +>same3 : Symbol(One.same3, Decl(intersectionOfCallsWithSameParameters.ts, 7, 42)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 8, 10)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 8, 21)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 8, 37)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 8, 51)) + + same4(id: string): { one: number }; +>same4 : Symbol(One.same4, Decl(intersectionOfCallsWithSameParameters.ts, 8, 66)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 9, 10)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 9, 22)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 9, 36)) + + same5(id: string): { one: number }; +>same5 : Symbol(One.same5, Decl(intersectionOfCallsWithSameParameters.ts, 9, 51)) +>T1 : Symbol(T1, Decl(intersectionOfCallsWithSameParameters.ts, 10, 10)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 10, 22)) +>T2 : Symbol(T2, Decl(intersectionOfCallsWithSameParameters.ts, 10, 37)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 10, 51)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 10, 65)) +} + +interface Two { +>Two : Symbol(Two, Decl(intersectionOfCallsWithSameParameters.ts, 11, 1)) + + differentParameterType(id: number): { two: number }; +>differentParameterType : Symbol(Two.differentParameterType, Decl(intersectionOfCallsWithSameParameters.ts, 13, 15)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 14, 27)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 14, 41)) + + differentNumberOfParameters(id: string, second: string): { two: number }; +>differentNumberOfParameters : Symbol(Two.differentNumberOfParameters, Decl(intersectionOfCallsWithSameParameters.ts, 14, 56)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 15, 32)) +>second : Symbol(second, Decl(intersectionOfCallsWithSameParameters.ts, 15, 43)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 15, 62)) + + differentTypeParameterDefault(id: string): { two: number }; +>differentTypeParameterDefault : Symbol(Two.differentTypeParameterDefault, Decl(intersectionOfCallsWithSameParameters.ts, 15, 77)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 16, 34)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 16, 46)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 16, 60)) + + differentTypeParameterConstraint(id: string): { two: number }; +>differentTypeParameterConstraint : Symbol(Two.differentTypeParameterConstraint, Decl(intersectionOfCallsWithSameParameters.ts, 16, 75)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 17, 37)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 17, 48)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 17, 64)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 17, 78)) + + same1(id: string): { two: number }; +>same1 : Symbol(Two.same1, Decl(intersectionOfCallsWithSameParameters.ts, 17, 93)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 19, 10)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 19, 24)) + + same2(id: string): { two: number }; +>same2 : Symbol(Two.same2, Decl(intersectionOfCallsWithSameParameters.ts, 19, 39)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 20, 10)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 20, 13)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 20, 27)) + + same3(id: string): { two: number }; +>same3 : Symbol(Two.same3, Decl(intersectionOfCallsWithSameParameters.ts, 20, 42)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 21, 10)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 21, 21)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 21, 37)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 21, 51)) + + same4(id: string): { two: number }; +>same4 : Symbol(Two.same4, Decl(intersectionOfCallsWithSameParameters.ts, 21, 66)) +>T : Symbol(T, Decl(intersectionOfCallsWithSameParameters.ts, 22, 10)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 22, 22)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 22, 36)) + + same5(id: string): { two: number }; +>same5 : Symbol(Two.same5, Decl(intersectionOfCallsWithSameParameters.ts, 22, 51)) +>T1 : Symbol(T1, Decl(intersectionOfCallsWithSameParameters.ts, 23, 10)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 23, 22)) +>T2 : Symbol(T2, Decl(intersectionOfCallsWithSameParameters.ts, 23, 37)) +>id : Symbol(id, Decl(intersectionOfCallsWithSameParameters.ts, 23, 51)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 23, 65)) +} + +const i: One & Two = {}; +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>One : Symbol(One, Decl(intersectionOfCallsWithSameParameters.ts, 0, 0)) +>Two : Symbol(Two, Decl(intersectionOfCallsWithSameParameters.ts, 11, 1)) + +// These lines should type check; the return type should be intersected. +const same1: { one: number, two: number } = i.same1('test'); +>same1 : Symbol(same1, Decl(intersectionOfCallsWithSameParameters.ts, 29, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 29, 14)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 29, 27)) +>i.same1 : Symbol(same1, Decl(intersectionOfCallsWithSameParameters.ts, 4, 93), Decl(intersectionOfCallsWithSameParameters.ts, 17, 93)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>same1 : Symbol(same1, Decl(intersectionOfCallsWithSameParameters.ts, 4, 93), Decl(intersectionOfCallsWithSameParameters.ts, 17, 93)) + +const same2: { one: number, two: number } = i.same2('test'); +>same2 : Symbol(same2, Decl(intersectionOfCallsWithSameParameters.ts, 30, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 30, 14)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 30, 27)) +>i.same2 : Symbol(same2, Decl(intersectionOfCallsWithSameParameters.ts, 6, 39), Decl(intersectionOfCallsWithSameParameters.ts, 19, 39)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>same2 : Symbol(same2, Decl(intersectionOfCallsWithSameParameters.ts, 6, 39), Decl(intersectionOfCallsWithSameParameters.ts, 19, 39)) + +const same3: { one: number, two: number } = i.same3<{ one:number }>('test'); +>same3 : Symbol(same3, Decl(intersectionOfCallsWithSameParameters.ts, 31, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 31, 14)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 31, 27)) +>i.same3 : Symbol(same3, Decl(intersectionOfCallsWithSameParameters.ts, 7, 42), Decl(intersectionOfCallsWithSameParameters.ts, 20, 42)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>same3 : Symbol(same3, Decl(intersectionOfCallsWithSameParameters.ts, 7, 42), Decl(intersectionOfCallsWithSameParameters.ts, 20, 42)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 31, 53)) + +const same4: { one: number, two: number } = i.same4('test'); +>same4 : Symbol(same4, Decl(intersectionOfCallsWithSameParameters.ts, 32, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 32, 14)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 32, 27)) +>i.same4 : Symbol(same4, Decl(intersectionOfCallsWithSameParameters.ts, 8, 66), Decl(intersectionOfCallsWithSameParameters.ts, 21, 66)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>same4 : Symbol(same4, Decl(intersectionOfCallsWithSameParameters.ts, 8, 66), Decl(intersectionOfCallsWithSameParameters.ts, 21, 66)) + +const same5: { one: number, two: number } = i.same5<{ one:number }, string>('test'); +>same5 : Symbol(same5, Decl(intersectionOfCallsWithSameParameters.ts, 33, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 33, 14)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 33, 27)) +>i.same5 : Symbol(same5, Decl(intersectionOfCallsWithSameParameters.ts, 9, 51), Decl(intersectionOfCallsWithSameParameters.ts, 22, 51)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>same5 : Symbol(same5, Decl(intersectionOfCallsWithSameParameters.ts, 9, 51), Decl(intersectionOfCallsWithSameParameters.ts, 22, 51)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 33, 53)) + +// These lines should not, because the functions should become overloads rather +// than the return types intersected. +const differentParameterType: { one: number, two: number } = i.differentParameterType('test'); +>differentParameterType : Symbol(differentParameterType, Decl(intersectionOfCallsWithSameParameters.ts, 37, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 37, 31)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 37, 44)) +>i.differentParameterType : Symbol(differentParameterType, Decl(intersectionOfCallsWithSameParameters.ts, 0, 15), Decl(intersectionOfCallsWithSameParameters.ts, 13, 15)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>differentParameterType : Symbol(differentParameterType, Decl(intersectionOfCallsWithSameParameters.ts, 0, 15), Decl(intersectionOfCallsWithSameParameters.ts, 13, 15)) + +const differentNumberOfParameters: { one: number, two: number } = i.differentNumberOfParameters('test'); +>differentNumberOfParameters : Symbol(differentNumberOfParameters, Decl(intersectionOfCallsWithSameParameters.ts, 38, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 38, 36)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 38, 49)) +>i.differentNumberOfParameters : Symbol(differentNumberOfParameters, Decl(intersectionOfCallsWithSameParameters.ts, 1, 56), Decl(intersectionOfCallsWithSameParameters.ts, 14, 56)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>differentNumberOfParameters : Symbol(differentNumberOfParameters, Decl(intersectionOfCallsWithSameParameters.ts, 1, 56), Decl(intersectionOfCallsWithSameParameters.ts, 14, 56)) + +const differentTypeParameterDefault: { one: number, two: number } = i.differentTypeParameterDefault('test'); +>differentTypeParameterDefault : Symbol(differentTypeParameterDefault, Decl(intersectionOfCallsWithSameParameters.ts, 39, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 39, 38)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 39, 51)) +>i.differentTypeParameterDefault : Symbol(differentTypeParameterDefault, Decl(intersectionOfCallsWithSameParameters.ts, 2, 61), Decl(intersectionOfCallsWithSameParameters.ts, 15, 77)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>differentTypeParameterDefault : Symbol(differentTypeParameterDefault, Decl(intersectionOfCallsWithSameParameters.ts, 2, 61), Decl(intersectionOfCallsWithSameParameters.ts, 15, 77)) + +const differentTypeParameterConstraint: { one: number, two: number } = i.differentTypeParameterConstraint<{ one: number }>('test'); +>differentTypeParameterConstraint : Symbol(differentTypeParameterConstraint, Decl(intersectionOfCallsWithSameParameters.ts, 40, 5)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 40, 41)) +>two : Symbol(two, Decl(intersectionOfCallsWithSameParameters.ts, 40, 54)) +>i.differentTypeParameterConstraint : Symbol(differentTypeParameterConstraint, Decl(intersectionOfCallsWithSameParameters.ts, 3, 75), Decl(intersectionOfCallsWithSameParameters.ts, 16, 75)) +>i : Symbol(i, Decl(intersectionOfCallsWithSameParameters.ts, 26, 5)) +>differentTypeParameterConstraint : Symbol(differentTypeParameterConstraint, Decl(intersectionOfCallsWithSameParameters.ts, 3, 75), Decl(intersectionOfCallsWithSameParameters.ts, 16, 75)) +>one : Symbol(one, Decl(intersectionOfCallsWithSameParameters.ts, 40, 107)) + diff --git a/tests/baselines/reference/intersectionOfCallsWithSameParameters.types b/tests/baselines/reference/intersectionOfCallsWithSameParameters.types new file mode 100644 index 0000000000000..9406022cdc472 --- /dev/null +++ b/tests/baselines/reference/intersectionOfCallsWithSameParameters.types @@ -0,0 +1,203 @@ +=== tests/cases/compiler/intersectionOfCallsWithSameParameters.ts === +interface One { + differentParameterType(id: string): { one: number }; +>differentParameterType : (id: string) => { one: number; } +>id : string +>one : number + + differentNumberOfParameters(id: string): { one: number }; +>differentNumberOfParameters : (id: string) => { one: number; } +>id : string +>one : number + + differentTypeParameterDefault(id: string): { one: number }; +>differentTypeParameterDefault : (id: string) => { one: number; } +>id : string +>one : number + + differentTypeParameterConstraint(id: string): { one: number }; +>differentTypeParameterConstraint : (id: string) => { one: number; } +>one : number +>id : string +>one : number + + same1(id: string): { one: number }; +>same1 : (id: string) => { one: number; } +>id : string +>one : number + + same2(id: string): { one: number }; +>same2 : (id: string) => { one: number; } +>id : string +>one : number + + same3(id: string): { one: number }; +>same3 : (id: string) => { one: number; } +>one : number +>id : string +>one : number + + same4(id: string): { one: number }; +>same4 : (id: string) => { one: number; } +>id : string +>one : number + + same5(id: string): { one: number }; +>same5 : (id: string) => { one: number; } +>one : number +>id : string +>one : number +} + +interface Two { + differentParameterType(id: number): { two: number }; +>differentParameterType : (id: number) => { two: number; } +>id : number +>two : number + + differentNumberOfParameters(id: string, second: string): { two: number }; +>differentNumberOfParameters : (id: string, second: string) => { two: number; } +>id : string +>second : string +>two : number + + differentTypeParameterDefault(id: string): { two: number }; +>differentTypeParameterDefault : (id: string) => { two: number; } +>id : string +>two : number + + differentTypeParameterConstraint(id: string): { two: number }; +>differentTypeParameterConstraint : (id: string) => { two: number; } +>two : number +>id : string +>two : number + + same1(id: string): { two: number }; +>same1 : (id: string) => { two: number; } +>id : string +>two : number + + same2(id: string): { two: number }; +>same2 : (id: string) => { two: number; } +>id : string +>two : number + + same3(id: string): { two: number }; +>same3 : (id: string) => { two: number; } +>one : number +>id : string +>two : number + + same4(id: string): { two: number }; +>same4 : (id: string) => { two: number; } +>id : string +>two : number + + same5(id: string): { two: number }; +>same5 : (id: string) => { two: number; } +>one : number +>id : string +>two : number +} + +const i: One & Two = {}; +>i : One & Two +>{} : any +>{} : {} + +// These lines should type check; the return type should be intersected. +const same1: { one: number, two: number } = i.same1('test'); +>same1 : { one: number; two: number; } +>one : number +>two : number +>i.same1('test') : { one: number; } & { two: number; } +>i.same1 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>i : One & Two +>same1 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>'test' : "test" + +const same2: { one: number, two: number } = i.same2('test'); +>same2 : { one: number; two: number; } +>one : number +>two : number +>i.same2('test') : { one: number; } & { two: number; } +>i.same2 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>i : One & Two +>same2 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>'test' : "test" + +const same3: { one: number, two: number } = i.same3<{ one:number }>('test'); +>same3 : { one: number; two: number; } +>one : number +>two : number +>i.same3<{ one:number }>('test') : { one: number; } & { two: number; } +>i.same3 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>i : One & Two +>same3 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>one : number +>'test' : "test" + +const same4: { one: number, two: number } = i.same4('test'); +>same4 : { one: number; two: number; } +>one : number +>two : number +>i.same4('test') : { one: number; } & { two: number; } +>i.same4 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>i : One & Two +>same4 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>'test' : "test" + +const same5: { one: number, two: number } = i.same5<{ one:number }, string>('test'); +>same5 : { one: number; two: number; } +>one : number +>two : number +>i.same5<{ one:number }, string>('test') : { one: number; } & { two: number; } +>i.same5 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>i : One & Two +>same5 : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>one : number +>'test' : "test" + +// These lines should not, because the functions should become overloads rather +// than the return types intersected. +const differentParameterType: { one: number, two: number } = i.differentParameterType('test'); +>differentParameterType : { one: number; two: number; } +>one : number +>two : number +>i.differentParameterType('test') : { one: number; } +>i.differentParameterType : ((id: string) => { one: number; }) & ((id: number) => { two: number; }) +>i : One & Two +>differentParameterType : ((id: string) => { one: number; }) & ((id: number) => { two: number; }) +>'test' : "test" + +const differentNumberOfParameters: { one: number, two: number } = i.differentNumberOfParameters('test'); +>differentNumberOfParameters : { one: number; two: number; } +>one : number +>two : number +>i.differentNumberOfParameters('test') : { one: number; } +>i.differentNumberOfParameters : ((id: string) => { one: number; }) & ((id: string, second: string) => { two: number; }) +>i : One & Two +>differentNumberOfParameters : ((id: string) => { one: number; }) & ((id: string, second: string) => { two: number; }) +>'test' : "test" + +const differentTypeParameterDefault: { one: number, two: number } = i.differentTypeParameterDefault('test'); +>differentTypeParameterDefault : { one: number; two: number; } +>one : number +>two : number +>i.differentTypeParameterDefault('test') : { one: number; } +>i.differentTypeParameterDefault : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>i : One & Two +>differentTypeParameterDefault : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>'test' : "test" + +const differentTypeParameterConstraint: { one: number, two: number } = i.differentTypeParameterConstraint<{ one: number }>('test'); +>differentTypeParameterConstraint : { one: number; two: number; } +>one : number +>two : number +>i.differentTypeParameterConstraint<{ one: number }>('test') : { one: number; } +>i.differentTypeParameterConstraint : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>i : One & Two +>differentTypeParameterConstraint : ((id: string) => { one: number; }) & ((id: string) => { two: number; }) +>one : number +>'test' : "test" + diff --git a/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.js b/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.js new file mode 100644 index 0000000000000..6ab75a0d2bee4 --- /dev/null +++ b/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.js @@ -0,0 +1,38 @@ +//// [twoTypeGuardsAllowUseOfFunctionReturnType.ts] +interface Opacity { + readonly opacity: number; + getStratum(id: string): { opacity: number }; +} + +interface Layer { + readonly layer: string; + getStratum(id: string): { layer: string }; +} + +function hasOpacity(x: any): x is Opacity { + return 'opacity' in x; +} + +function hasLayer(x: any): x is Layer { + return 'layer' in x; +} + +const foo = {}; +if (hasOpacity(foo) && hasLayer(foo)) { + foo.getStratum('user').opacity = 0.5; + foo.getStratum('user').layer = 'test'; +} + + +//// [twoTypeGuardsAllowUseOfFunctionReturnType.js] +function hasOpacity(x) { + return 'opacity' in x; +} +function hasLayer(x) { + return 'layer' in x; +} +var foo = {}; +if (hasOpacity(foo) && hasLayer(foo)) { + foo.getStratum('user').opacity = 0.5; + foo.getStratum('user').layer = 'test'; +} diff --git a/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.symbols b/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.symbols new file mode 100644 index 0000000000000..a5a2cc9ae624d --- /dev/null +++ b/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.symbols @@ -0,0 +1,69 @@ +=== tests/cases/compiler/twoTypeGuardsAllowUseOfFunctionReturnType.ts === +interface Opacity { +>Opacity : Symbol(Opacity, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 0, 0)) + + readonly opacity: number; +>opacity : Symbol(Opacity.opacity, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 0, 19)) + + getStratum(id: string): { opacity: number }; +>getStratum : Symbol(Opacity.getStratum, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 1, 29)) +>id : Symbol(id, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 2, 15)) +>opacity : Symbol(opacity, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 2, 29)) +} + +interface Layer { +>Layer : Symbol(Layer, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 3, 1)) + + readonly layer: string; +>layer : Symbol(Layer.layer, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 5, 17)) + + getStratum(id: string): { layer: string }; +>getStratum : Symbol(Layer.getStratum, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 6, 27)) +>id : Symbol(id, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 7, 15)) +>layer : Symbol(layer, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 7, 29)) +} + +function hasOpacity(x: any): x is Opacity { +>hasOpacity : Symbol(hasOpacity, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 8, 1)) +>x : Symbol(x, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 10, 20)) +>x : Symbol(x, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 10, 20)) +>Opacity : Symbol(Opacity, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 0, 0)) + + return 'opacity' in x; +>x : Symbol(x, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 10, 20)) +} + +function hasLayer(x: any): x is Layer { +>hasLayer : Symbol(hasLayer, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 12, 1)) +>x : Symbol(x, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 14, 18)) +>x : Symbol(x, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 14, 18)) +>Layer : Symbol(Layer, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 3, 1)) + + return 'layer' in x; +>x : Symbol(x, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 14, 18)) +} + +const foo = {}; +>foo : Symbol(foo, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 18, 5)) + +if (hasOpacity(foo) && hasLayer(foo)) { +>hasOpacity : Symbol(hasOpacity, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 8, 1)) +>foo : Symbol(foo, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 18, 5)) +>hasLayer : Symbol(hasLayer, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 12, 1)) +>foo : Symbol(foo, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 18, 5)) + + foo.getStratum('user').opacity = 0.5; +>foo.getStratum('user').opacity : Symbol(opacity, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 2, 29)) +>foo.getStratum : Symbol(getStratum, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 1, 29), Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 6, 27)) +>foo : Symbol(foo, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 18, 5)) +>getStratum : Symbol(getStratum, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 1, 29), Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 6, 27)) +>opacity : Symbol(opacity, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 2, 29)) + + foo.getStratum('user').layer = 'test'; +>foo.getStratum('user').layer : Symbol(layer, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 7, 29)) +>foo.getStratum : Symbol(getStratum, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 1, 29), Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 6, 27)) +>foo : Symbol(foo, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 18, 5)) +>getStratum : Symbol(getStratum, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 1, 29), Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 6, 27)) +>layer : Symbol(layer, Decl(twoTypeGuardsAllowUseOfFunctionReturnType.ts, 7, 29)) +} + diff --git a/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.types b/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.types new file mode 100644 index 0000000000000..7c383be8d5f22 --- /dev/null +++ b/tests/baselines/reference/twoTypeGuardsAllowUseOfFunctionReturnType.types @@ -0,0 +1,77 @@ +=== tests/cases/compiler/twoTypeGuardsAllowUseOfFunctionReturnType.ts === +interface Opacity { + readonly opacity: number; +>opacity : number + + getStratum(id: string): { opacity: number }; +>getStratum : (id: string) => { opacity: number; } +>id : string +>opacity : number +} + +interface Layer { + readonly layer: string; +>layer : string + + getStratum(id: string): { layer: string }; +>getStratum : (id: string) => { layer: string; } +>id : string +>layer : string +} + +function hasOpacity(x: any): x is Opacity { +>hasOpacity : (x: any) => x is Opacity +>x : any + + return 'opacity' in x; +>'opacity' in x : boolean +>'opacity' : "opacity" +>x : any +} + +function hasLayer(x: any): x is Layer { +>hasLayer : (x: any) => x is Layer +>x : any + + return 'layer' in x; +>'layer' in x : boolean +>'layer' : "layer" +>x : any +} + +const foo = {}; +>foo : {} +>{} : {} + +if (hasOpacity(foo) && hasLayer(foo)) { +>hasOpacity(foo) && hasLayer(foo) : boolean +>hasOpacity(foo) : boolean +>hasOpacity : (x: any) => x is Opacity +>foo : {} +>hasLayer(foo) : boolean +>hasLayer : (x: any) => x is Layer +>foo : Opacity + + foo.getStratum('user').opacity = 0.5; +>foo.getStratum('user').opacity = 0.5 : 0.5 +>foo.getStratum('user').opacity : number +>foo.getStratum('user') : { opacity: number; } & { layer: string; } +>foo.getStratum : ((id: string) => { opacity: number; }) & ((id: string) => { layer: string; }) +>foo : Opacity & Layer +>getStratum : ((id: string) => { opacity: number; }) & ((id: string) => { layer: string; }) +>'user' : "user" +>opacity : number +>0.5 : 0.5 + + foo.getStratum('user').layer = 'test'; +>foo.getStratum('user').layer = 'test' : "test" +>foo.getStratum('user').layer : string +>foo.getStratum('user') : { opacity: number; } & { layer: string; } +>foo.getStratum : ((id: string) => { opacity: number; }) & ((id: string) => { layer: string; }) +>foo : Opacity & Layer +>getStratum : ((id: string) => { opacity: number; }) & ((id: string) => { layer: string; }) +>'user' : "user" +>layer : string +>'test' : "test" +} + diff --git a/tests/cases/compiler/intersectionOfCallsWithSameParameters.ts b/tests/cases/compiler/intersectionOfCallsWithSameParameters.ts new file mode 100644 index 0000000000000..95aa2628e9187 --- /dev/null +++ b/tests/cases/compiler/intersectionOfCallsWithSameParameters.ts @@ -0,0 +1,43 @@ +// @strict: true + +interface One { + differentParameterType(id: string): { one: number }; + differentNumberOfParameters(id: string): { one: number }; + differentTypeParameterDefault(id: string): { one: number }; + differentTypeParameterConstraint(id: string): { one: number }; + + same1(id: string): { one: number }; + same2(id: string): { one: number }; + same3(id: string): { one: number }; + same4(id: string): { one: number }; + same5(id: string): { one: number }; +} + +interface Two { + differentParameterType(id: number): { two: number }; + differentNumberOfParameters(id: string, second: string): { two: number }; + differentTypeParameterDefault(id: string): { two: number }; + differentTypeParameterConstraint(id: string): { two: number }; + + same1(id: string): { two: number }; + same2(id: string): { two: number }; + same3(id: string): { two: number }; + same4(id: string): { two: number }; + same5(id: string): { two: number }; +} + +const i: One & Two = {}; + +// These lines should type check; the return type should be intersected. +const same1: { one: number, two: number } = i.same1('test'); +const same2: { one: number, two: number } = i.same2('test'); +const same3: { one: number, two: number } = i.same3<{ one:number }>('test'); +const same4: { one: number, two: number } = i.same4('test'); +const same5: { one: number, two: number } = i.same5<{ one:number }, string>('test'); + +// These lines should not, because the functions should become overloads rather +// than the return types intersected. +const differentParameterType: { one: number, two: number } = i.differentParameterType('test'); +const differentNumberOfParameters: { one: number, two: number } = i.differentNumberOfParameters('test'); +const differentTypeParameterDefault: { one: number, two: number } = i.differentTypeParameterDefault('test'); +const differentTypeParameterConstraint: { one: number, two: number } = i.differentTypeParameterConstraint<{ one: number }>('test'); diff --git a/tests/cases/compiler/twoTypeGuardsAllowUseOfFunctionReturnType.ts b/tests/cases/compiler/twoTypeGuardsAllowUseOfFunctionReturnType.ts new file mode 100644 index 0000000000000..b3c0156008cd3 --- /dev/null +++ b/tests/cases/compiler/twoTypeGuardsAllowUseOfFunctionReturnType.ts @@ -0,0 +1,23 @@ +interface Opacity { + readonly opacity: number; + getStratum(id: string): { opacity: number }; +} + +interface Layer { + readonly layer: string; + getStratum(id: string): { layer: string }; +} + +function hasOpacity(x: any): x is Opacity { + return 'opacity' in x; +} + +function hasLayer(x: any): x is Layer { + return 'layer' in x; +} + +const foo = {}; +if (hasOpacity(foo) && hasLayer(foo)) { + foo.getStratum('user').opacity = 0.5; + foo.getStratum('user').layer = 'test'; +}