diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7c7fab735856e..707d0b8119549 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10219,7 +10219,8 @@ namespace ts { sig.resolvedMinArgumentCount = undefined; sig.target = undefined; sig.mapper = undefined; - sig.unionSignatures = undefined; + sig.compositeSignatures = undefined; + sig.compositeKind = undefined; return sig; } @@ -10228,13 +10229,15 @@ namespace ts { /*resolvedTypePredicate*/ undefined, sig.minArgumentCount, sig.flags & SignatureFlags.PropagatingFlags); result.target = sig.target; result.mapper = sig.mapper; - result.unionSignatures = sig.unionSignatures; + result.compositeSignatures = sig.compositeSignatures; + result.compositeKind = sig.compositeKind; return result; } function createUnionSignature(signature: Signature, unionSignatures: Signature[]) { const result = cloneSignature(signature); - result.unionSignatures = unionSignatures; + result.compositeSignatures = unionSignatures; + result.compositeKind = TypeFlags.Union; result.target = undefined; result.mapper = undefined; return result; @@ -10398,7 +10401,7 @@ namespace ts { if (signatures !== masterList) { const signature = signatures[0]; Debug.assert(!!signature, "getUnionSignatures bails early on empty signature lists and should not have empty lists on second pass"); - results = signature.typeParameters && some(results, s => !!s.typeParameters && !compareTypeParametersIdentical(signature.typeParameters!, s.typeParameters)) ? undefined : map(results, sig => combineSignaturesOfUnionMembers(sig, signature)); + results = !!signature.typeParameters && some(results, s => !!s.typeParameters && !compareTypeParametersIdentical(signature.typeParameters, s.typeParameters)) ? undefined : map(results, sig => combineSignaturesOfUnionMembers(sig, signature)); if (!results) { break; } @@ -10409,10 +10412,13 @@ namespace ts { return result || emptyArray; } - function compareTypeParametersIdentical(sourceParams: readonly TypeParameter[], targetParams: readonly TypeParameter[]): boolean { - if (sourceParams.length !== targetParams.length) { + function compareTypeParametersIdentical(sourceParams: readonly TypeParameter[] | undefined, targetParams: readonly TypeParameter[] | undefined): boolean { + if (length(sourceParams) !== length(targetParams)) { return false; } + if (!sourceParams || !targetParams) { + return true; + } const mapper = createTypeMapper(targetParams, sourceParams); for (let i = 0; i < sourceParams.length; i++) { @@ -10508,9 +10514,10 @@ namespace ts { minArgCount, (left.flags | right.flags) & SignatureFlags.PropagatingFlags ); - result.unionSignatures = concatenate(left.unionSignatures || [left], [right]); + result.compositeKind = TypeFlags.Union; + result.compositeSignatures = concatenate(left.compositeKind !== TypeFlags.Intersection && left.compositeSignatures || [left], [right]); if (paramMapper) { - result.mapper = left.mapper && left.unionSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; + result.mapper = left.compositeKind !== TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; } return result; } @@ -12028,8 +12035,8 @@ namespace ts { const targetTypePredicate = getTypePredicateOfSignature(signature.target); signature.resolvedTypePredicate = targetTypePredicate ? instantiateTypePredicate(targetTypePredicate, signature.mapper!) : noTypePredicate; } - else if (signature.unionSignatures) { - signature.resolvedTypePredicate = getUnionTypePredicate(signature.unionSignatures) || noTypePredicate; + else if (signature.compositeSignatures) { + signature.resolvedTypePredicate = getUnionOrIntersectionTypePredicate(signature.compositeSignatures, signature.compositeKind) || noTypePredicate; } else { const type = signature.declaration && getEffectiveReturnTypeNode(signature.declaration); @@ -12058,13 +12065,17 @@ namespace ts { findIndex(signature.parameters, p => p.escapedName === parameterName.escapedText), type); } + function getUnionOrIntersectionType(types: Type[], kind: TypeFlags | undefined, unionReduction?: UnionReduction) { + return kind !== TypeFlags.Intersection ? getUnionType(types, unionReduction) : getIntersectionType(types); + } + function getReturnTypeOfSignature(signature: Signature): Type { if (!signature.resolvedReturnType) { if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) { return errorType; } let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper) : - signature.unionSignatures ? instantiateType(getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype), signature.mapper) : + signature.compositeSignatures ? instantiateType(getUnionOrIntersectionType(map(signature.compositeSignatures, getReturnTypeOfSignature), signature.compositeKind, UnionReduction.Subtype), signature.mapper) : getReturnTypeFromAnnotation(signature.declaration!) || (nodeIsMissing((signature.declaration).body) ? anyType : getReturnTypeFromBody(signature.declaration)); if (signature.flags & SignatureFlags.IsInnerCallChain) { @@ -13487,13 +13498,18 @@ namespace ts { return getUnionTypeFromSortedList(typeSet, objectFlags, aliasSymbol, aliasTypeArguments, origin); } - function getUnionTypePredicate(signatures: readonly Signature[]): TypePredicate | undefined { + function getUnionOrIntersectionTypePredicate(signatures: readonly Signature[], kind: TypeFlags | undefined): TypePredicate | undefined { let first: TypePredicate | undefined; const types: Type[] = []; for (const sig of signatures) { const pred = getTypePredicateOfSignature(sig); if (!pred || pred.kind === TypePredicateKind.AssertsThis || pred.kind === TypePredicateKind.AssertsIdentifier) { - continue; + if (kind !== TypeFlags.Intersection) { + continue; + } + else { + return; // intersections demand all members be type predicates for the result to have a predicate + } } if (first) { @@ -13508,11 +13524,11 @@ namespace ts { types.push(pred.type); } if (!first) { - // No union signatures had a type predicate. + // No signatures had a type predicate. return undefined; } - const unionType = getUnionType(types); - return createTypePredicate(first.kind, first.parameterName, first.parameterIndex, unionType); + const compositeType = getUnionOrIntersectionType(types, kind); + return createTypePredicate(first.kind, first.parameterName, first.parameterIndex, compositeType); } function typePredicateKindsMatch(a: TypePredicate, b: TypePredicate): boolean { @@ -24826,14 +24842,14 @@ namespace ts { } function getJsxPropsTypeForSignatureFromMember(sig: Signature, forcedLookupLocation: __String) { - if (sig.unionSignatures) { + if (sig.compositeSignatures) { // JSX Elements using the legacy `props`-field based lookup (eg, react class components) need to treat the `props` member as an input // instead of an output position when resolving the signature. We need to go back to the input signatures of the composite signature, // get the type of `props` on each return type individually, and then _intersect them_, rather than union them (as would normally occur // for a union signature). It's an unfortunate quirk of looking in the output of the signature for the type we want to use for the input. // The default behavior of `getTypeOfFirstParameterOfSignatureWithFallback` when no `props` member name is defined is much more sane. const results: Type[] = []; - for (const signature of sig.unionSignatures) { + for (const signature of sig.compositeSignatures) { const instance = getReturnTypeOfSignature(signature); if (isTypeAny(instance)) { return instance; @@ -24844,7 +24860,7 @@ namespace ts { } results.push(propType); } - return getIntersectionType(results); + return getIntersectionType(results); // Same result for both union and intersection signatures } const instanceType = getReturnTypeOfSignature(sig); return isTypeAny(instanceType) ? instanceType : getTypeOfPropertyOfType(instanceType, forcedLookupLocation); @@ -24938,16 +24954,109 @@ namespace ts { } } + function getIntersectedSignatures(signatures: readonly Signature[]) { + return getStrictOptionValue(compilerOptions, "noImplicitAny") + ? reduceLeft( + signatures, + (left, right) => + left === right || !left ? left + : compareTypeParametersIdentical(left.typeParameters, right.typeParameters) ? combineSignaturesOfIntersectionMembers(left, right) + : undefined) + : undefined; + } + + function combineIntersectionThisParam(left: Symbol | undefined, right: Symbol | undefined, mapper: TypeMapper | undefined): Symbol | undefined { + if (!left || !right) { + return left || right; + } + // A signature `this` type might be a read or a write position... It's very possible that it should be invariant + // and we should refuse to merge signatures if there are `this` types and they do not match. However, so as to be + // pessimistic when contextual typing, for now, we'll union the `this` types. + const thisType = getUnionType([getTypeOfSymbol(left), instantiateType(getTypeOfSymbol(right), mapper)]); + return createSymbolWithType(left, thisType); + } + + function combineIntersectionParameters(left: Signature, right: Signature, mapper: TypeMapper | undefined) { + const leftCount = getParameterCount(left); + const rightCount = getParameterCount(right); + const longest = leftCount >= rightCount ? left : right; + const shorter = longest === left ? right : left; + const longestCount = longest === left ? leftCount : rightCount; + const eitherHasEffectiveRest = (hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right)); + const needsExtraRestElement = eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); + const params = new Array(longestCount + (needsExtraRestElement ? 1 : 0)); + for (let i = 0; i < longestCount; i++) { + let longestParamType = tryGetTypeAtPosition(longest, i)!; + if (longest === right) { + longestParamType = instantiateType(longestParamType, mapper); + } + let shorterParamType = tryGetTypeAtPosition(shorter, i) || unknownType; + if (shorter === right) { + shorterParamType = instantiateType(shorterParamType, mapper); + } + const unionParamType = getUnionType([longestParamType, shorterParamType]); + const isRestParam = eitherHasEffectiveRest && !needsExtraRestElement && i === (longestCount - 1); + const isOptional = i >= getMinArgumentCount(longest) && i >= getMinArgumentCount(shorter); + const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); + const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); + + const paramName = leftName === rightName ? leftName : + !leftName ? rightName : + !rightName ? leftName : + undefined; + const paramSymbol = createSymbol( + SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), + paramName || `arg${i}` as __String + ); + paramSymbol.type = isRestParam ? createArrayType(unionParamType) : unionParamType; + params[i] = paramSymbol; + } + if (needsExtraRestElement) { + const restParamSymbol = createSymbol(SymbolFlags.FunctionScopedVariable, "args" as __String); + restParamSymbol.type = createArrayType(getTypeAtPosition(shorter, longestCount)); + if (shorter === right) { + restParamSymbol.type = instantiateType(restParamSymbol.type, mapper); + } + params[longestCount] = restParamSymbol; + } + return params; + } + + function combineSignaturesOfIntersectionMembers(left: Signature, right: Signature): Signature { + const typeParams = left.typeParameters || right.typeParameters; + let paramMapper: TypeMapper | undefined; + if (left.typeParameters && right.typeParameters) { + paramMapper = createTypeMapper(right.typeParameters, left.typeParameters); + // We just use the type parameter defaults from the first signature + } + const declaration = left.declaration; + const params = combineIntersectionParameters(left, right, paramMapper); + const thisParam = combineIntersectionThisParam(left.thisParameter, right.thisParameter, paramMapper); + const minArgCount = Math.max(left.minArgumentCount, right.minArgumentCount); + const result = createSignature( + declaration, + typeParams, + thisParam, + params, + /*resolvedReturnType*/ undefined, + /*resolvedTypePredicate*/ undefined, + minArgCount, + (left.flags | right.flags) & SignatureFlags.PropagatingFlags + ); + result.compositeKind = TypeFlags.Intersection; + result.compositeSignatures = concatenate(left.compositeKind === TypeFlags.Intersection && left.compositeSignatures || [left], [right]); + if (paramMapper) { + result.mapper = left.compositeKind === TypeFlags.Intersection && left.mapper && left.compositeSignatures ? combineTypeMappers(left.mapper, paramMapper) : paramMapper; + } + return result; + } + // If the given type is an object or union type with a single signature, and if that signature has at // least as many parameters as the given function, return the signature. Otherwise return undefined. function getContextualCallSignature(type: Type, node: SignatureDeclaration): Signature | undefined { const signatures = getSignaturesOfType(type, SignatureKind.Call); - if (signatures.length === 1) { - const signature = signatures[0]; - if (!isAritySmaller(signature, node)) { - return signature; - } - } + const applicableByArity = filter(signatures, s => !isAritySmaller(s, node)); + return applicableByArity.length === 1 ? applicableByArity[0] : getIntersectedSignatures(applicableByArity); } /** If the contextual signature has fewer parameters than the function expression, do not use it */ diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9f3042896223e..ce85b94583e2f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5548,7 +5548,9 @@ namespace ts { /* @internal */ mapper?: TypeMapper; // Instantiation mapper /* @internal */ - unionSignatures?: Signature[]; // Underlying signatures of a union signature + compositeSignatures?: Signature[]; // Underlying signatures of a union/intersection signature + /* @internal */ + compositeKind?: TypeFlags; // TypeFlags.Union if the underlying signatures are from union members, otherwise TypeFlags.Intersection /* @internal */ erasedSignatureCache?: Signature; // Erased version of signature (deferred) /* @internal */ diff --git a/tests/baselines/reference/callsOnComplexSignatures.errors.txt b/tests/baselines/reference/callsOnComplexSignatures.errors.txt deleted file mode 100644 index f85a23e4ae79d..0000000000000 --- a/tests/baselines/reference/callsOnComplexSignatures.errors.txt +++ /dev/null @@ -1,110 +0,0 @@ -tests/cases/compiler/callsOnComplexSignatures.tsx(38,19): error TS7006: Parameter 'item' implicitly has an 'any' type. - - -==== tests/cases/compiler/callsOnComplexSignatures.tsx (1 errors) ==== - /// - import React from "react"; - - // Simple calls from real usecases - function test1() { - type stringType1 = "foo" | "bar"; - type stringType2 = "baz" | "bar"; - - interface Temp1 { - getValue(name: stringType1): number; - } - - interface Temp2 { - getValue(name: stringType2): string; - } - - function test(t: Temp1 | Temp2) { - const z = t.getValue("bar"); // Should be fine - } - } - - function test2() { - interface Messages { - readonly foo: (options: { [key: string]: any, b: number }) => string; - readonly bar: (options: { [key: string]: any, a: string }) => string; - } - - const messages: Messages = { - foo: (options) => "Foo", - bar: (options) => "Bar", - }; - - const test1 = (type: "foo" | "bar") => - messages[type]({ a: "A", b: 0 }); - } - - function test3(items: string[] | number[]) { - items.forEach(item => console.log(item)); - ~~~~ -!!! error TS7006: Parameter 'item' implicitly has an 'any' type. - } - - function test4( - arg1: ((...objs: {x: number}[]) => number) | ((...objs: {y: number}[]) => number), - arg2: ((a: {x: number}, b: object) => number) | ((a: object, b: {x: number}) => number), - arg3: ((a: {x: number}, ...objs: {y: number}[]) => number) | ((...objs: {x: number}[]) => number), - arg4: ((a?: {x: number}, b?: {x: number}) => number) | ((a?: {y: number}) => number), - arg5: ((a?: {x: number}, ...b: {x: number}[]) => number) | ((a?: {y: number}) => number), - arg6: ((a?: {x: number}, b?: {x: number}) => number) | ((...a: {y: number}[]) => number), - ) { - arg1(); - arg1({x: 0, y: 0}); - arg1({x: 0, y: 0}, {x: 1, y: 1}); - - arg2({x: 0}, {x: 0}); - - arg3({x: 0}); - arg3({x: 0}, {x: 0, y: 0}); - arg3({x: 0}, {x: 0, y: 0}, {x: 0, y: 0}); - - arg4(); - arg4({x: 0, y: 0}); - arg4({x: 0, y: 0}, {x: 0}); - - arg5(); - arg5({x: 0, y: 0}); - arg5({x: 0, y: 0}, {x: 0}); - - arg6(); - arg6({x: 0, y: 0}); - arg6({x: 0, y: 0}, {x: 0, y: 0}); - arg6({x: 0, y: 0}, {x: 0, y: 0}, {y: 0}); - } - - // JSX Tag names - function test5() { - // Pair of non-like intrinsics - function render(url?: string): React.ReactNode { - const Tag = url ? 'a' : 'button'; - return test; - } - - // Union of all intrinsics and components of `any` - function App(props: { component:React.ReactType }) { - const Comp: React.ReactType = props.component; - return (); - } - - // custom components with non-subset props - function render2() { - interface P1 { - p?: boolean; - c?: string; - } - interface P2 { - p?: boolean; - c?: any; - d?: any; - } - - var C: React.ComponentType | React.ComponentType = null as any; - - const a = ; - } - } - \ No newline at end of file diff --git a/tests/baselines/reference/callsOnComplexSignatures.types b/tests/baselines/reference/callsOnComplexSignatures.types index 1fa6c1f44e29a..a255300662666 100644 --- a/tests/baselines/reference/callsOnComplexSignatures.types +++ b/tests/baselines/reference/callsOnComplexSignatures.types @@ -100,13 +100,13 @@ function test3(items: string[] | number[]) { >items.forEach : ((callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void) | ((callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void) >items : string[] | number[] >forEach : ((callbackfn: (value: string, index: number, array: string[]) => void, thisArg?: any) => void) | ((callbackfn: (value: number, index: number, array: number[]) => void, thisArg?: any) => void) ->item => console.log(item) : (item: any) => void ->item : any +>item => console.log(item) : (item: string | number) => void +>item : string | number >console.log(item) : void >console.log : (...data: any[]) => void >console : Console >log : (...data: any[]) => void ->item : any +>item : string | number } function test4( diff --git a/tests/baselines/reference/circularlySimplifyingConditionalTypesNoCrash.types b/tests/baselines/reference/circularlySimplifyingConditionalTypesNoCrash.types index 073b9d326163f..a6c312de9005d 100644 --- a/tests/baselines/reference/circularlySimplifyingConditionalTypesNoCrash.types +++ b/tests/baselines/reference/circularlySimplifyingConditionalTypesNoCrash.types @@ -56,7 +56,7 @@ declare var connect: Connect; const myStoreConnect: Connect = function( >myStoreConnect : Connect ->function( mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options: unknown = {},) { return connect( mapStateToProps, mapDispatchToProps, mergeProps, options, );} : (mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options?: unknown) => InferableComponentEnhancerWithProps +>function( mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options: unknown = {},) { return connect( mapStateToProps, mapDispatchToProps, mergeProps, options, );} : (mapStateToProps?: any, mapDispatchToProps?: any, mergeProps?: any, options?: unknown) => InferableComponentEnhancerWithProps> & TOwnProps> mapStateToProps?: any, >mapStateToProps : any @@ -73,7 +73,7 @@ const myStoreConnect: Connect = function( ) { return connect( ->connect( mapStateToProps, mapDispatchToProps, mergeProps, options, ) : InferableComponentEnhancerWithProps +>connect( mapStateToProps, mapDispatchToProps, mergeProps, options, ) : InferableComponentEnhancerWithProps> & TOwnProps> >connect : Connect mapStateToProps, diff --git a/tests/baselines/reference/contextualOverloadListFromArrayUnion.js b/tests/baselines/reference/contextualOverloadListFromArrayUnion.js new file mode 100644 index 0000000000000..b1b8f45cb2688 --- /dev/null +++ b/tests/baselines/reference/contextualOverloadListFromArrayUnion.js @@ -0,0 +1,111 @@ +//// [tests/cases/compiler/contextualOverloadListFromArrayUnion.ts] //// + +//// [one.ts] +declare const y: never[] | string[]; +export const yThen = y.map(item => item.length); +//// [two.ts] +declare const y: number[][] | string[]; +export const yThen = y.map(item => item.length); +//// [three.ts] +// #42504 +interface ResizeObserverCallback { + (entries: ResizeObserverEntry[], observer: ResizeObserver): void; +} +interface ResizeObserverCallback { // duplicate for effect + (entries: ResizeObserverEntry[], observer: ResizeObserver): void; +} + +const resizeObserver = new ResizeObserver(([entry]) => { + entry +}); +// comment in #35501 +interface Callback { + (error: null, result: T): unknown + (error: Error, result: null): unknown +} + +interface Task { + (callback: Callback): unknown +} + +export function series(tasks: Task[], callback: Callback): void { + let index = 0 + let results: T[] = [] + + function next() { + let task = tasks[index] + if (!task) { + callback(null, results) + } else { + task((error, result) => { + if (error) { + callback(error, null) + } else { + // must use postfix-!, since `error` and `result` don't have a + // causal relationship when the overloads are combined + results.push(result!) + next() + } + }) + } + } + next() +} + +series([ + cb => setTimeout(() => cb(null, 1), 300), + cb => setTimeout(() => cb(null, 2), 200), + cb => setTimeout(() => cb(null, 3), 100), +], (error, results) => { + if (error) { + console.error(error) + } else { + console.log(results) + } +}) + + +//// [one.js] +export const yThen = y.map(item => item.length); +//// [two.js] +export const yThen = y.map(item => item.length); +//// [three.js] +const resizeObserver = new ResizeObserver(([entry]) => { + entry; +}); +export function series(tasks, callback) { + let index = 0; + let results = []; + function next() { + let task = tasks[index]; + if (!task) { + callback(null, results); + } + else { + task((error, result) => { + if (error) { + callback(error, null); + } + else { + // must use postfix-!, since `error` and `result` don't have a + // causal relationship when the overloads are combined + results.push(result); + next(); + } + }); + } + } + next(); +} +series([ + cb => setTimeout(() => cb(null, 1), 300), + cb => setTimeout(() => cb(null, 2), 200), + cb => setTimeout(() => cb(null, 3), 100), +], (error, results) => { + if (error) { + console.error(error); + } + else { + console.log(results); + } +}); diff --git a/tests/baselines/reference/contextualOverloadListFromArrayUnion.symbols b/tests/baselines/reference/contextualOverloadListFromArrayUnion.symbols new file mode 100644 index 0000000000000..7762be3ab737b --- /dev/null +++ b/tests/baselines/reference/contextualOverloadListFromArrayUnion.symbols @@ -0,0 +1,188 @@ +=== tests/cases/compiler/one.ts === +declare const y: never[] | string[]; +>y : Symbol(y, Decl(one.ts, 0, 13)) + +export const yThen = y.map(item => item.length); +>yThen : Symbol(yThen, Decl(one.ts, 1, 12)) +>y.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>y : Symbol(y, Decl(one.ts, 0, 13)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>item : Symbol(item, Decl(one.ts, 1, 27)) +>item.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) +>item : Symbol(item, Decl(one.ts, 1, 27)) +>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) + +=== tests/cases/compiler/two.ts === +declare const y: number[][] | string[]; +>y : Symbol(y, Decl(two.ts, 0, 13)) + +export const yThen = y.map(item => item.length); +>yThen : Symbol(yThen, Decl(two.ts, 1, 12)) +>y.map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>y : Symbol(y, Decl(two.ts, 0, 13)) +>map : Symbol(Array.map, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>item : Symbol(item, Decl(two.ts, 1, 27)) +>item.length : Symbol(length, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>item : Symbol(item, Decl(two.ts, 1, 27)) +>length : Symbol(length, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +=== tests/cases/compiler/three.ts === +// #42504 +interface ResizeObserverCallback { +>ResizeObserverCallback : Symbol(ResizeObserverCallback, Decl(three.ts, 0, 0), Decl(three.ts, 3, 1)) + + (entries: ResizeObserverEntry[], observer: ResizeObserver): void; +>entries : Symbol(entries, Decl(three.ts, 2, 5)) +>ResizeObserverEntry : Symbol(ResizeObserverEntry, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>observer : Symbol(observer, Decl(three.ts, 2, 36)) +>ResizeObserver : Symbol(ResizeObserver, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +} +interface ResizeObserverCallback { // duplicate for effect +>ResizeObserverCallback : Symbol(ResizeObserverCallback, Decl(three.ts, 0, 0), Decl(three.ts, 3, 1)) + + (entries: ResizeObserverEntry[], observer: ResizeObserver): void; +>entries : Symbol(entries, Decl(three.ts, 5, 5)) +>ResizeObserverEntry : Symbol(ResizeObserverEntry, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>observer : Symbol(observer, Decl(three.ts, 5, 36)) +>ResizeObserver : Symbol(ResizeObserver, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +} + +const resizeObserver = new ResizeObserver(([entry]) => { +>resizeObserver : Symbol(resizeObserver, Decl(three.ts, 8, 5)) +>ResizeObserver : Symbol(ResizeObserver, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>entry : Symbol(entry, Decl(three.ts, 8, 44)) + + entry +>entry : Symbol(entry, Decl(three.ts, 8, 44)) + +}); +// comment in #35501 +interface Callback { +>Callback : Symbol(Callback, Decl(three.ts, 10, 3)) +>T : Symbol(T, Decl(three.ts, 12, 19)) + + (error: null, result: T): unknown +>error : Symbol(error, Decl(three.ts, 13, 5)) +>result : Symbol(result, Decl(three.ts, 13, 17)) +>T : Symbol(T, Decl(three.ts, 12, 19)) + + (error: Error, result: null): unknown +>error : Symbol(error, Decl(three.ts, 14, 5)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>result : Symbol(result, Decl(three.ts, 14, 18)) +} + +interface Task { +>Task : Symbol(Task, Decl(three.ts, 15, 1)) +>T : Symbol(T, Decl(three.ts, 17, 15)) + + (callback: Callback): unknown +>callback : Symbol(callback, Decl(three.ts, 18, 5)) +>Callback : Symbol(Callback, Decl(three.ts, 10, 3)) +>T : Symbol(T, Decl(three.ts, 17, 15)) +} + +export function series(tasks: Task[], callback: Callback): void { +>series : Symbol(series, Decl(three.ts, 19, 1)) +>T : Symbol(T, Decl(three.ts, 21, 23)) +>tasks : Symbol(tasks, Decl(three.ts, 21, 26)) +>Task : Symbol(Task, Decl(three.ts, 15, 1)) +>T : Symbol(T, Decl(three.ts, 21, 23)) +>callback : Symbol(callback, Decl(three.ts, 21, 43)) +>Callback : Symbol(Callback, Decl(three.ts, 10, 3)) +>T : Symbol(T, Decl(three.ts, 21, 23)) + + let index = 0 +>index : Symbol(index, Decl(three.ts, 22, 7)) + + let results: T[] = [] +>results : Symbol(results, Decl(three.ts, 23, 7)) +>T : Symbol(T, Decl(three.ts, 21, 23)) + + function next() { +>next : Symbol(next, Decl(three.ts, 23, 25)) + + let task = tasks[index] +>task : Symbol(task, Decl(three.ts, 26, 11)) +>tasks : Symbol(tasks, Decl(three.ts, 21, 26)) +>index : Symbol(index, Decl(three.ts, 22, 7)) + + if (!task) { +>task : Symbol(task, Decl(three.ts, 26, 11)) + + callback(null, results) +>callback : Symbol(callback, Decl(three.ts, 21, 43)) +>results : Symbol(results, Decl(three.ts, 23, 7)) + + } else { + task((error, result) => { +>task : Symbol(task, Decl(three.ts, 26, 11)) +>error : Symbol(error, Decl(three.ts, 30, 18)) +>result : Symbol(result, Decl(three.ts, 30, 24)) + + if (error) { +>error : Symbol(error, Decl(three.ts, 30, 18)) + + callback(error, null) +>callback : Symbol(callback, Decl(three.ts, 21, 43)) +>error : Symbol(error, Decl(three.ts, 30, 18)) + + } else { + // must use postfix-!, since `error` and `result` don't have a + // causal relationship when the overloads are combined + results.push(result!) +>results.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>results : Symbol(results, Decl(three.ts, 23, 7)) +>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --)) +>result : Symbol(result, Decl(three.ts, 30, 24)) + + next() +>next : Symbol(next, Decl(three.ts, 23, 25)) + } + }) + } + } + next() +>next : Symbol(next, Decl(three.ts, 23, 25)) +} + +series([ +>series : Symbol(series, Decl(three.ts, 19, 1)) + + cb => setTimeout(() => cb(null, 1), 300), +>cb : Symbol(cb, Decl(three.ts, 45, 8)) +>setTimeout : Symbol(setTimeout, Decl(lib.dom.d.ts, --, --)) +>cb : Symbol(cb, Decl(three.ts, 45, 8)) + + cb => setTimeout(() => cb(null, 2), 200), +>cb : Symbol(cb, Decl(three.ts, 46, 45)) +>setTimeout : Symbol(setTimeout, Decl(lib.dom.d.ts, --, --)) +>cb : Symbol(cb, Decl(three.ts, 46, 45)) + + cb => setTimeout(() => cb(null, 3), 100), +>cb : Symbol(cb, Decl(three.ts, 47, 45)) +>setTimeout : Symbol(setTimeout, Decl(lib.dom.d.ts, --, --)) +>cb : Symbol(cb, Decl(three.ts, 47, 45)) + +], (error, results) => { +>error : Symbol(error, Decl(three.ts, 49, 4)) +>results : Symbol(results, Decl(three.ts, 49, 10)) + + if (error) { +>error : Symbol(error, Decl(three.ts, 49, 4)) + + console.error(error) +>console.error : Symbol(Console.error, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>error : Symbol(Console.error, Decl(lib.dom.d.ts, --, --)) +>error : Symbol(error, Decl(three.ts, 49, 4)) + + } else { + console.log(results) +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>results : Symbol(results, Decl(three.ts, 49, 10)) + } +}) + diff --git a/tests/baselines/reference/contextualOverloadListFromArrayUnion.types b/tests/baselines/reference/contextualOverloadListFromArrayUnion.types new file mode 100644 index 0000000000000..f42e54a0cec7d --- /dev/null +++ b/tests/baselines/reference/contextualOverloadListFromArrayUnion.types @@ -0,0 +1,212 @@ +=== tests/cases/compiler/one.ts === +declare const y: never[] | string[]; +>y : never[] | string[] + +export const yThen = y.map(item => item.length); +>yThen : number[] +>y.map(item => item.length) : number[] +>y.map : ((callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) +>y : never[] | string[] +>map : ((callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) +>item => item.length : (item: string) => number +>item : string +>item.length : number +>item : string +>length : number + +=== tests/cases/compiler/two.ts === +declare const y: number[][] | string[]; +>y : string[] | number[][] + +export const yThen = y.map(item => item.length); +>yThen : number[] +>y.map(item => item.length) : number[] +>y.map : ((callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: number[], index: number, array: number[][]) => U, thisArg?: any) => U[]) +>y : string[] | number[][] +>map : ((callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: number[], index: number, array: number[][]) => U, thisArg?: any) => U[]) +>item => item.length : (item: string | number[]) => number +>item : string | number[] +>item.length : number +>item : string | number[] +>length : number + +=== tests/cases/compiler/three.ts === +// #42504 +interface ResizeObserverCallback { + (entries: ResizeObserverEntry[], observer: ResizeObserver): void; +>entries : ResizeObserverEntry[] +>observer : ResizeObserver +} +interface ResizeObserverCallback { // duplicate for effect + (entries: ResizeObserverEntry[], observer: ResizeObserver): void; +>entries : ResizeObserverEntry[] +>observer : ResizeObserver +} + +const resizeObserver = new ResizeObserver(([entry]) => { +>resizeObserver : ResizeObserver +>new ResizeObserver(([entry]) => { entry}) : ResizeObserver +>ResizeObserver : { new (callback: globalThis.ResizeObserverCallback): ResizeObserver; prototype: ResizeObserver; } +>([entry]) => { entry} : ([entry]: ResizeObserverEntry[]) => void +>entry : ResizeObserverEntry + + entry +>entry : ResizeObserverEntry + +}); +// comment in #35501 +interface Callback { + (error: null, result: T): unknown +>error : null +>null : null +>result : T + + (error: Error, result: null): unknown +>error : Error +>result : null +>null : null +} + +interface Task { + (callback: Callback): unknown +>callback : Callback +} + +export function series(tasks: Task[], callback: Callback): void { +>series : (tasks: Task[], callback: Callback) => void +>tasks : Task[] +>callback : Callback + + let index = 0 +>index : number +>0 : 0 + + let results: T[] = [] +>results : T[] +>[] : never[] + + function next() { +>next : () => void + + let task = tasks[index] +>task : Task +>tasks[index] : Task +>tasks : Task[] +>index : number + + if (!task) { +>!task : false +>task : Task + + callback(null, results) +>callback(null, results) : unknown +>callback : Callback +>null : null +>results : T[] + + } else { + task((error, result) => { +>task((error, result) => { if (error) { callback(error, null) } else { // must use postfix-!, since `error` and `result` don't have a // causal relationship when the overloads are combined results.push(result!) next() } }) : unknown +>task : Task +>(error, result) => { if (error) { callback(error, null) } else { // must use postfix-!, since `error` and `result` don't have a // causal relationship when the overloads are combined results.push(result!) next() } } : (error: Error | null, result: T | null) => void +>error : Error | null +>result : T | null + + if (error) { +>error : Error | null + + callback(error, null) +>callback(error, null) : unknown +>callback : Callback +>error : Error +>null : null + + } else { + // must use postfix-!, since `error` and `result` don't have a + // causal relationship when the overloads are combined + results.push(result!) +>results.push(result!) : number +>results.push : (...items: T[]) => number +>results : T[] +>push : (...items: T[]) => number +>result! : NonNullable +>result : T | null + + next() +>next() : void +>next : () => void + } + }) + } + } + next() +>next() : void +>next : () => void +} + +series([ +>series([ cb => setTimeout(() => cb(null, 1), 300), cb => setTimeout(() => cb(null, 2), 200), cb => setTimeout(() => cb(null, 3), 100),], (error, results) => { if (error) { console.error(error) } else { console.log(results) }}) : void +>series : (tasks: Task[], callback: Callback) => void +>[ cb => setTimeout(() => cb(null, 1), 300), cb => setTimeout(() => cb(null, 2), 200), cb => setTimeout(() => cb(null, 3), 100),] : ((cb: Callback) => number)[] + + cb => setTimeout(() => cb(null, 1), 300), +>cb => setTimeout(() => cb(null, 1), 300) : (cb: Callback) => number +>cb : Callback +>setTimeout(() => cb(null, 1), 300) : number +>setTimeout : (handler: TimerHandler, timeout?: number | undefined, ...arguments: any[]) => number +>() => cb(null, 1) : () => unknown +>cb(null, 1) : unknown +>cb : Callback +>null : null +>1 : 1 +>300 : 300 + + cb => setTimeout(() => cb(null, 2), 200), +>cb => setTimeout(() => cb(null, 2), 200) : (cb: Callback) => number +>cb : Callback +>setTimeout(() => cb(null, 2), 200) : number +>setTimeout : (handler: TimerHandler, timeout?: number | undefined, ...arguments: any[]) => number +>() => cb(null, 2) : () => unknown +>cb(null, 2) : unknown +>cb : Callback +>null : null +>2 : 2 +>200 : 200 + + cb => setTimeout(() => cb(null, 3), 100), +>cb => setTimeout(() => cb(null, 3), 100) : (cb: Callback) => number +>cb : Callback +>setTimeout(() => cb(null, 3), 100) : number +>setTimeout : (handler: TimerHandler, timeout?: number | undefined, ...arguments: any[]) => number +>() => cb(null, 3) : () => unknown +>cb(null, 3) : unknown +>cb : Callback +>null : null +>3 : 3 +>100 : 100 + +], (error, results) => { +>(error, results) => { if (error) { console.error(error) } else { console.log(results) }} : (error: Error | null, results: unknown[] | null) => void +>error : Error | null +>results : unknown[] | null + + if (error) { +>error : Error | null + + console.error(error) +>console.error(error) : void +>console.error : (...data: any[]) => void +>console : Console +>error : (...data: any[]) => void +>error : Error + + } else { + console.log(results) +>console.log(results) : void +>console.log : (...data: any[]) => void +>console : Console +>log : (...data: any[]) => void +>results : unknown[] | null + } +}) + diff --git a/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.errors.txt b/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.errors.txt new file mode 100644 index 0000000000000..8877c033a1c68 --- /dev/null +++ b/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.errors.txt @@ -0,0 +1,21 @@ +tests/cases/compiler/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts(13,20): error TS7006: Parameter 'match' implicitly has an 'any' type. + + +==== tests/cases/compiler/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts (1 errors) ==== + // must target esnext for `String.normalize` to exist + type Validate = (text: string, pos: number, self: Rule) => number | boolean; + interface FullRule { + validate: string | RegExp | Validate; + normalize?: (match: {x: string}) => void; + } + + type Rule = string | FullRule; + + const obj: {field: Rule} = { + field: { + validate: (_t, _p, _s) => false, + normalize: match => match.x, + ~~~~~ +!!! error TS7006: Parameter 'match' implicitly has an 'any' type. + } + }; \ No newline at end of file diff --git a/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.js b/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.js new file mode 100644 index 0000000000000..a53e1dd3a85fc --- /dev/null +++ b/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.js @@ -0,0 +1,25 @@ +//// [contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts] +// must target esnext for `String.normalize` to exist +type Validate = (text: string, pos: number, self: Rule) => number | boolean; +interface FullRule { + validate: string | RegExp | Validate; + normalize?: (match: {x: string}) => void; +} + +type Rule = string | FullRule; + +const obj: {field: Rule} = { + field: { + validate: (_t, _p, _s) => false, + normalize: match => match.x, + } +}; + +//// [contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.js] +"use strict"; +const obj = { + field: { + validate: (_t, _p, _s) => false, + normalize: match => match.x, + } +}; diff --git a/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.symbols b/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.symbols new file mode 100644 index 0000000000000..c26b811a86b2b --- /dev/null +++ b/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.symbols @@ -0,0 +1,47 @@ +=== tests/cases/compiler/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts === +// must target esnext for `String.normalize` to exist +type Validate = (text: string, pos: number, self: Rule) => number | boolean; +>Validate : Symbol(Validate, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 0, 0)) +>text : Symbol(text, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 1, 17)) +>pos : Symbol(pos, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 1, 30)) +>self : Symbol(self, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 1, 43)) +>Rule : Symbol(Rule, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 5, 1)) + +interface FullRule { +>FullRule : Symbol(FullRule, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 1, 76)) + + validate: string | RegExp | Validate; +>validate : Symbol(FullRule.validate, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 2, 20)) +>RegExp : Symbol(RegExp, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.regexp.d.ts, --, --) ... and 1 more) +>Validate : Symbol(Validate, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 0, 0)) + + normalize?: (match: {x: string}) => void; +>normalize : Symbol(FullRule.normalize, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 3, 41)) +>match : Symbol(match, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 4, 17)) +>x : Symbol(x, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 4, 25)) +} + +type Rule = string | FullRule; +>Rule : Symbol(Rule, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 5, 1)) +>FullRule : Symbol(FullRule, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 1, 76)) + +const obj: {field: Rule} = { +>obj : Symbol(obj, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 9, 5)) +>field : Symbol(field, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 9, 12)) +>Rule : Symbol(Rule, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 5, 1)) + + field: { +>field : Symbol(field, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 9, 28)) + + validate: (_t, _p, _s) => false, +>validate : Symbol(validate, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 10, 12)) +>_t : Symbol(_t, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 11, 19)) +>_p : Symbol(_p, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 11, 22)) +>_s : Symbol(_s, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 11, 26)) + + normalize: match => match.x, +>normalize : Symbol(normalize, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 11, 40)) +>match : Symbol(match, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 12, 18)) +>match : Symbol(match, Decl(contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts, 12, 18)) + } +}; diff --git a/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.types b/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.types new file mode 100644 index 0000000000000..c9a236a44ef10 --- /dev/null +++ b/tests/baselines/reference/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.types @@ -0,0 +1,47 @@ +=== tests/cases/compiler/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts === +// must target esnext for `String.normalize` to exist +type Validate = (text: string, pos: number, self: Rule) => number | boolean; +>Validate : Validate +>text : string +>pos : number +>self : Rule + +interface FullRule { + validate: string | RegExp | Validate; +>validate : string | RegExp | Validate + + normalize?: (match: {x: string}) => void; +>normalize : ((match: { x: string;}) => void) | undefined +>match : { x: string; } +>x : string +} + +type Rule = string | FullRule; +>Rule : Rule + +const obj: {field: Rule} = { +>obj : { field: Rule; } +>field : Rule +>{ field: { validate: (_t, _p, _s) => false, normalize: match => match.x, }} : { field: { validate: (_t: string, _p: number, _s: Rule) => false; normalize: (match: any) => any; }; } + + field: { +>field : { validate: (_t: string, _p: number, _s: Rule) => false; normalize: (match: any) => any; } +>{ validate: (_t, _p, _s) => false, normalize: match => match.x, } : { validate: (_t: string, _p: number, _s: Rule) => false; normalize: (match: any) => any; } + + validate: (_t, _p, _s) => false, +>validate : (_t: string, _p: number, _s: Rule) => false +>(_t, _p, _s) => false : (_t: string, _p: number, _s: Rule) => false +>_t : string +>_p : number +>_s : Rule +>false : false + + normalize: match => match.x, +>normalize : (match: any) => any +>match => match.x : (match: any) => any +>match : any +>match.x : any +>match : any +>x : any + } +}; diff --git a/tests/baselines/reference/redefineArray.errors.txt b/tests/baselines/reference/redefineArray.errors.txt index e59c0e9e24a1c..55390de55ae7b 100644 --- a/tests/baselines/reference/redefineArray.errors.txt +++ b/tests/baselines/reference/redefineArray.errors.txt @@ -1,8 +1,8 @@ -tests/cases/compiler/redefineArray.ts(1,1): error TS2741: Property 'isArray' is missing in type '(n: number, s: string) => number' but required in type 'ArrayConstructor'. +tests/cases/compiler/redefineArray.ts(1,1): error TS2741: Property 'isArray' is missing in type '(n: number, s: string) => number' but required in type 'ArrayConstructor'. ==== tests/cases/compiler/redefineArray.ts (1 errors) ==== Array = function (n:number, s:string) {return n;}; ~~~~~ -!!! error TS2741: Property 'isArray' is missing in type '(n: number, s: string) => number' but required in type 'ArrayConstructor'. +!!! error TS2741: Property 'isArray' is missing in type '(n: number, s: string) => number' but required in type 'ArrayConstructor'. !!! related TS2728 /.ts/lib.es5.d.ts:1411:5: 'isArray' is declared here. \ No newline at end of file diff --git a/tests/baselines/reference/redefineArray.types b/tests/baselines/reference/redefineArray.types index 51b1e67846b2c..2eb4d14f69950 100644 --- a/tests/baselines/reference/redefineArray.types +++ b/tests/baselines/reference/redefineArray.types @@ -1,8 +1,8 @@ === tests/cases/compiler/redefineArray.ts === Array = function (n:number, s:string) {return n;}; ->Array = function (n:number, s:string) {return n;} : (n: number, s: string) => number +>Array = function (n:number, s:string) {return n;} : (n: number, s: string) => number >Array : ArrayConstructor ->function (n:number, s:string) {return n;} : (n: number, s: string) => number +>function (n:number, s:string) {return n;} : (n: number, s: string) => number >n : number >s : string >n : number diff --git a/tests/cases/compiler/contextualOverloadListFromArrayUnion.ts b/tests/cases/compiler/contextualOverloadListFromArrayUnion.ts new file mode 100644 index 0000000000000..eb0d45ef43504 --- /dev/null +++ b/tests/cases/compiler/contextualOverloadListFromArrayUnion.ts @@ -0,0 +1,65 @@ +// @strict: true +// @target: es6 +// @filename: one.ts +declare const y: never[] | string[]; +export const yThen = y.map(item => item.length); +// @filename: two.ts +declare const y: number[][] | string[]; +export const yThen = y.map(item => item.length); +// @filename: three.ts +// #42504 +interface ResizeObserverCallback { + (entries: ResizeObserverEntry[], observer: ResizeObserver): void; +} +interface ResizeObserverCallback { // duplicate for effect + (entries: ResizeObserverEntry[], observer: ResizeObserver): void; +} + +const resizeObserver = new ResizeObserver(([entry]) => { + entry +}); +// comment in #35501 +interface Callback { + (error: null, result: T): unknown + (error: Error, result: null): unknown +} + +interface Task { + (callback: Callback): unknown +} + +export function series(tasks: Task[], callback: Callback): void { + let index = 0 + let results: T[] = [] + + function next() { + let task = tasks[index] + if (!task) { + callback(null, results) + } else { + task((error, result) => { + if (error) { + callback(error, null) + } else { + // must use postfix-!, since `error` and `result` don't have a + // causal relationship when the overloads are combined + results.push(result!) + next() + } + }) + } + } + next() +} + +series([ + cb => setTimeout(() => cb(null, 1), 300), + cb => setTimeout(() => cb(null, 2), 200), + cb => setTimeout(() => cb(null, 3), 100), +], (error, results) => { + if (error) { + console.error(error) + } else { + console.log(results) + } +}) diff --git a/tests/cases/compiler/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts b/tests/cases/compiler/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts new file mode 100644 index 0000000000000..0d61c7e0609d5 --- /dev/null +++ b/tests/cases/compiler/contextualOverloadListFromUnionWithPrimitiveNoImplicitAny.ts @@ -0,0 +1,17 @@ +// @strict: true +// @target: esnext +// must target esnext for `String.normalize` to exist +type Validate = (text: string, pos: number, self: Rule) => number | boolean; +interface FullRule { + validate: string | RegExp | Validate; + normalize?: (match: {x: string}) => void; +} + +type Rule = string | FullRule; + +const obj: {field: Rule} = { + field: { + validate: (_t, _p, _s) => false, + normalize: match => match.x, + } +}; \ No newline at end of file