mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
Merge pull request #32460 from microsoft/fix32434
Improve type inference for types like 'T | Promise<T>'
This commit is contained in:
@@ -13540,6 +13540,9 @@ namespace ts {
|
||||
if (relation !== identityRelation) {
|
||||
source = getApparentType(source);
|
||||
}
|
||||
else if (isGenericMappedType(source)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target &&
|
||||
!(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) {
|
||||
// We have type references to the same generic type, and the type references are not marker
|
||||
@@ -15456,9 +15459,11 @@ namespace ts {
|
||||
|
||||
function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0, contravariant = false) {
|
||||
let symbolStack: Symbol[];
|
||||
let visited: Map<boolean>;
|
||||
let visited: Map<number>;
|
||||
let bivariant = false;
|
||||
let propagationType: Type;
|
||||
let inferenceCount = 0;
|
||||
let inferenceIncomplete = false;
|
||||
let allowComplexConstraintInference = true;
|
||||
inferFromTypes(originalSource, originalTarget);
|
||||
|
||||
@@ -15500,23 +15505,28 @@ namespace ts {
|
||||
// of all their possible values.
|
||||
let matchingTypes: Type[] | undefined;
|
||||
for (const t of (<UnionOrIntersectionType>source).types) {
|
||||
if (typeIdenticalToSomeType(t, (<UnionOrIntersectionType>target).types)) {
|
||||
(matchingTypes || (matchingTypes = [])).push(t);
|
||||
inferFromTypes(t, t);
|
||||
}
|
||||
else if (t.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral)) {
|
||||
const b = getBaseTypeOfLiteralType(t);
|
||||
if (typeIdenticalToSomeType(b, (<UnionOrIntersectionType>target).types)) {
|
||||
(matchingTypes || (matchingTypes = [])).push(t, b);
|
||||
}
|
||||
const matched = findMatchedType(t, <UnionOrIntersectionType>target);
|
||||
if (matched) {
|
||||
(matchingTypes || (matchingTypes = [])).push(matched);
|
||||
inferFromTypes(matched, matched);
|
||||
}
|
||||
}
|
||||
// Next, to improve the quality of inferences, reduce the source and target types by
|
||||
// removing the identically matched constituents. For example, when inferring from
|
||||
// 'string | string[]' to 'string | T' we reduce the types to 'string[]' and 'T'.
|
||||
if (matchingTypes) {
|
||||
source = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>source, matchingTypes);
|
||||
target = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>target, matchingTypes);
|
||||
const s = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>source, matchingTypes);
|
||||
const t = removeTypesFromUnionOrIntersection(<UnionOrIntersectionType>target, matchingTypes);
|
||||
if (!(s && t)) return;
|
||||
source = s;
|
||||
target = t;
|
||||
}
|
||||
}
|
||||
else if (target.flags & TypeFlags.Union && !(target.flags & TypeFlags.EnumLiteral) || target.flags & TypeFlags.Intersection) {
|
||||
const matched = findMatchedType(source, <UnionOrIntersectionType>target);
|
||||
if (matched) {
|
||||
inferFromTypes(matched, matched);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) {
|
||||
@@ -15562,13 +15572,14 @@ namespace ts {
|
||||
clearCachedInferences(inferences);
|
||||
}
|
||||
}
|
||||
inferenceCount++;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// Infer to the simplified version of an indexed access, if possible, to (hopefully) expose more bare type parameters to the inference engine
|
||||
const simplified = getSimplifiedType(target, /*writing*/ false);
|
||||
if (simplified !== target) {
|
||||
inferFromTypesOnce(source, simplified);
|
||||
invokeOnce(source, simplified, inferFromTypes);
|
||||
}
|
||||
else if (target.flags & TypeFlags.IndexedAccess) {
|
||||
const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false);
|
||||
@@ -15577,13 +15588,14 @@ namespace ts {
|
||||
if (indexType.flags & TypeFlags.Instantiable) {
|
||||
const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false);
|
||||
if (simplified && simplified !== target) {
|
||||
inferFromTypesOnce(source, simplified);
|
||||
invokeOnce(source, simplified, inferFromTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
|
||||
if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (
|
||||
(<TypeReference>source).target === (<TypeReference>target).target || isArrayType(source) && isArrayType(target))) {
|
||||
// If source and target are references to the same generic type, infer from type arguments
|
||||
inferFromTypeArguments((<TypeReference>source).typeArguments || emptyArray, (<TypeReference>target).typeArguments || emptyArray, getVariances((<TypeReference>source).target));
|
||||
}
|
||||
@@ -15613,10 +15625,10 @@ namespace ts {
|
||||
}
|
||||
else if (target.flags & TypeFlags.Conditional && !contravariant) {
|
||||
const targetTypes = [getTrueTypeFromConditionalType(<ConditionalType>target), getFalseTypeFromConditionalType(<ConditionalType>target)];
|
||||
inferToMultipleTypes(source, targetTypes, /*isIntersection*/ false);
|
||||
inferToMultipleTypes(source, targetTypes, target.flags);
|
||||
}
|
||||
else if (target.flags & TypeFlags.UnionOrIntersection) {
|
||||
inferToMultipleTypes(source, (<UnionOrIntersectionType>target).types, !!(target.flags & TypeFlags.Intersection));
|
||||
inferToMultipleTypes(source, (<UnionOrIntersectionType>target).types, target.flags);
|
||||
}
|
||||
else if (source.flags & TypeFlags.Union) {
|
||||
// Source is a union or intersection type, infer from each constituent type
|
||||
@@ -15645,39 +15657,22 @@ namespace ts {
|
||||
source = apparentSource;
|
||||
}
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
||||
const key = source.id + "," + target.id;
|
||||
if (visited && visited.get(key)) {
|
||||
return;
|
||||
}
|
||||
(visited || (visited = createMap<boolean>())).set(key, true);
|
||||
// If we are already processing another target type with the same associated symbol (such as
|
||||
// an instantiation of the same generic type), we do not explore this target as it would yield
|
||||
// no further inferences. We exclude the static side of classes from this check since it shares
|
||||
// its symbol with the instance side which would lead to false positives.
|
||||
const isNonConstructorObject = target.flags & TypeFlags.Object &&
|
||||
!(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class);
|
||||
const symbol = isNonConstructorObject ? target.symbol : undefined;
|
||||
if (symbol) {
|
||||
if (contains(symbolStack, symbol)) {
|
||||
return;
|
||||
}
|
||||
(symbolStack || (symbolStack = [])).push(symbol);
|
||||
inferFromObjectTypes(source, target);
|
||||
symbolStack.pop();
|
||||
}
|
||||
else {
|
||||
inferFromObjectTypes(source, target);
|
||||
}
|
||||
invokeOnce(source, target, inferFromObjectTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function inferFromTypesOnce(source: Type, target: Type) {
|
||||
const key = source.id + "," + target.id;
|
||||
if (!visited || !visited.get(key)) {
|
||||
(visited || (visited = createMap<boolean>())).set(key, true);
|
||||
inferFromTypes(source, target);
|
||||
}
|
||||
function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) {
|
||||
const key = source.id + "," + target.id;
|
||||
const count = visited && visited.get(key);
|
||||
if (count !== undefined) {
|
||||
inferenceCount += count;
|
||||
return;
|
||||
}
|
||||
(visited || (visited = createMap<number>())).set(key, 0);
|
||||
const startCount = inferenceCount;
|
||||
action(source, target);
|
||||
visited.set(key, inferenceCount - startCount);
|
||||
}
|
||||
|
||||
function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) {
|
||||
@@ -15714,24 +15709,60 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function inferToMultipleTypes(source: Type, targets: Type[], isIntersection: boolean) {
|
||||
// We infer from types that are not naked type variables first so that inferences we
|
||||
// make from nested naked type variables and given slightly higher priority by virtue
|
||||
// of being first in the candidates array.
|
||||
function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) {
|
||||
let typeVariableCount = 0;
|
||||
for (const t of targets) {
|
||||
if (getInferenceInfoForType(t)) {
|
||||
typeVariableCount++;
|
||||
if (targetFlags & TypeFlags.Union) {
|
||||
let nakedTypeVariable: Type | undefined;
|
||||
const sources = source.flags & TypeFlags.Union ? (<UnionType>source).types : [source];
|
||||
const matched = new Array<boolean>(sources.length);
|
||||
const saveInferenceIncomplete = inferenceIncomplete;
|
||||
inferenceIncomplete = false;
|
||||
// First infer to types that are not naked type variables. For each source type we
|
||||
// track whether inferences were made from that particular type to some target.
|
||||
for (const t of targets) {
|
||||
if (getInferenceInfoForType(t)) {
|
||||
nakedTypeVariable = t;
|
||||
typeVariableCount++;
|
||||
}
|
||||
else {
|
||||
for (let i = 0; i < sources.length; i++) {
|
||||
const count = inferenceCount;
|
||||
inferFromTypes(sources[i], t);
|
||||
if (count !== inferenceCount) matched[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
inferFromTypes(source, t);
|
||||
const inferenceComplete = !inferenceIncomplete;
|
||||
inferenceIncomplete = inferenceIncomplete || saveInferenceIncomplete;
|
||||
// If the target has a single naked type variable and inference completed (meaning we
|
||||
// explored the types fully), create a union of the source types from which no inferences
|
||||
// have been made so far and infer from that union to the naked type variable.
|
||||
if (typeVariableCount === 1 && inferenceComplete) {
|
||||
const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s);
|
||||
if (unmatched.length) {
|
||||
inferFromTypes(getUnionType(unmatched), nakedTypeVariable!);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We infer from types that are not naked type variables first so that inferences we
|
||||
// make from nested naked type variables and given slightly higher priority by virtue
|
||||
// of being first in the candidates array.
|
||||
for (const t of targets) {
|
||||
if (getInferenceInfoForType(t)) {
|
||||
typeVariableCount++;
|
||||
}
|
||||
else {
|
||||
inferFromTypes(source, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Inferences directly to naked type variables are given lower priority as they are
|
||||
// less specific. For example, when inferring from Promise<string> to T | Promise<T>,
|
||||
// we want to infer string for T, not Promise<string> | string. For intersection types
|
||||
// we only infer to single naked type variables.
|
||||
if (isIntersection ? typeVariableCount === 1 : typeVariableCount !== 0) {
|
||||
if (targetFlags & TypeFlags.Intersection ? typeVariableCount === 1 : typeVariableCount > 0) {
|
||||
const savePriority = priority;
|
||||
priority |= InferencePriority.NakedTypeVariable;
|
||||
for (const t of targets) {
|
||||
@@ -15800,6 +15831,28 @@ namespace ts {
|
||||
}
|
||||
|
||||
function inferFromObjectTypes(source: Type, target: Type) {
|
||||
// If we are already processing another target type with the same associated symbol (such as
|
||||
// an instantiation of the same generic type), we do not explore this target as it would yield
|
||||
// no further inferences. We exclude the static side of classes from this check since it shares
|
||||
// its symbol with the instance side which would lead to false positives.
|
||||
const isNonConstructorObject = target.flags & TypeFlags.Object &&
|
||||
!(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class);
|
||||
const symbol = isNonConstructorObject ? target.symbol : undefined;
|
||||
if (symbol) {
|
||||
if (contains(symbolStack, symbol)) {
|
||||
inferenceIncomplete = true;
|
||||
return;
|
||||
}
|
||||
(symbolStack || (symbolStack = [])).push(symbol);
|
||||
inferFromObjectTypesWorker(source, target);
|
||||
symbolStack.pop();
|
||||
}
|
||||
else {
|
||||
inferFromObjectTypesWorker(source, target);
|
||||
}
|
||||
}
|
||||
|
||||
function inferFromObjectTypesWorker(source: Type, target: Type) {
|
||||
if (isGenericMappedType(source) && isGenericMappedType(target)) {
|
||||
// The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer
|
||||
// from S to T and from X to Y.
|
||||
@@ -15902,15 +15955,35 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function typeIdenticalToSomeType(type: Type, types: Type[]): boolean {
|
||||
function isMatchableType(type: Type) {
|
||||
// We exclude non-anonymous object types because some frameworks (e.g. Ember) rely on the ability to
|
||||
// infer between types that don't witness their type variables. Such types would otherwise be eliminated
|
||||
// because they appear identical.
|
||||
return !(type.flags & TypeFlags.Object) || !!(getObjectFlags(type) & ObjectFlags.Anonymous);
|
||||
}
|
||||
|
||||
function typeMatchedBySomeType(type: Type, types: Type[]): boolean {
|
||||
for (const t of types) {
|
||||
if (isTypeIdenticalTo(t, type)) {
|
||||
if (t === type || isMatchableType(t) && isMatchableType(type) && isTypeIdenticalTo(t, type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function findMatchedType(type: Type, target: UnionOrIntersectionType) {
|
||||
if (typeMatchedBySomeType(type, target.types)) {
|
||||
return type;
|
||||
}
|
||||
if (type.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral) && target.flags & TypeFlags.Union) {
|
||||
const base = getBaseTypeOfLiteralType(type);
|
||||
if (typeMatchedBySomeType(base, target.types)) {
|
||||
return base;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new union or intersection type computed by removing a given set of types
|
||||
* from a given union or intersection type.
|
||||
@@ -15918,11 +15991,11 @@ namespace ts {
|
||||
function removeTypesFromUnionOrIntersection(type: UnionOrIntersectionType, typesToRemove: Type[]) {
|
||||
const reducedTypes: Type[] = [];
|
||||
for (const t of type.types) {
|
||||
if (!typeIdenticalToSomeType(t, typesToRemove)) {
|
||||
if (!typeMatchedBySomeType(t, typesToRemove)) {
|
||||
reducedTypes.push(t);
|
||||
}
|
||||
}
|
||||
return type.flags & TypeFlags.Union ? getUnionType(reducedTypes) : getIntersectionType(reducedTypes);
|
||||
return reducedTypes.length ? type.flags & TypeFlags.Union ? getUnionType(reducedTypes) : getIntersectionType(reducedTypes) : undefined;
|
||||
}
|
||||
|
||||
function hasPrimitiveConstraint(type: TypeParameter): boolean {
|
||||
|
||||
@@ -20,7 +20,7 @@ var e1: number | string | boolean;
|
||||
>e1 : string | number | boolean
|
||||
|
||||
f1(a1); // string
|
||||
>f1(a1) : string
|
||||
>f1(a1) : unknown
|
||||
>f1 : <T>(x: string | T) => T
|
||||
>a1 : string
|
||||
|
||||
|
||||
@@ -1,38 +1,61 @@
|
||||
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(9,15): error TS2345: Argument of type '2' is not assignable to parameter of type 'string | 1'.
|
||||
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(13,24): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
|
||||
tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts(31,15): error TS2345: Argument of type '42' is not assignable to parameter of type 'never'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (1 errors) ====
|
||||
// Verify that inferences made *to* a type parameter in a union type are secondary
|
||||
// to inferences made directly to that type parameter
|
||||
==== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts (2 errors) ====
|
||||
declare const b: boolean;
|
||||
declare const s: string;
|
||||
declare const sn: string | number;
|
||||
|
||||
function f<T>(x: T, y: string|T): T {
|
||||
return x;
|
||||
declare function f1<T>(x: T, y: string | T): T;
|
||||
|
||||
const a1 = f1(1, 2); // 1 | 2
|
||||
const a2 = f1(1, "hello"); // 1
|
||||
const a3 = f1(1, sn); // number
|
||||
const a4 = f1(undefined, "abc"); // undefined
|
||||
const a5 = f1("foo", "bar"); // "foo"
|
||||
const a6 = f1(true, false); // boolean
|
||||
const a7 = f1("hello", 1); // Error
|
||||
~
|
||||
!!! error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
|
||||
|
||||
declare function f2<T>(value: [string, T]): T;
|
||||
|
||||
var b1 = f2(["string", true]); // boolean
|
||||
|
||||
declare function f3<T>(x: string | false | T): T;
|
||||
|
||||
const c1 = f3(5); // 5
|
||||
const c2 = f3(sn); // number
|
||||
const c3 = f3(true); // true
|
||||
const c4 = f3(b); // true
|
||||
const c5 = f3("abc"); // never
|
||||
|
||||
declare function f4<T>(x: string & T): T;
|
||||
|
||||
const d1 = f4("abc");
|
||||
const d2 = f4(s);
|
||||
const d3 = f4(42); // Error
|
||||
~~
|
||||
!!! error TS2345: Argument of type '42' is not assignable to parameter of type 'never'.
|
||||
|
||||
export interface Foo<T> {
|
||||
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
|
||||
}
|
||||
export interface Bar<T> {
|
||||
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
|
||||
}
|
||||
|
||||
var a1: number;
|
||||
var a1 = f(1, 2);
|
||||
~
|
||||
!!! error TS2345: Argument of type '2' is not assignable to parameter of type 'string | 1'.
|
||||
var a2: number;
|
||||
var a2 = f(1, "hello");
|
||||
var a3: number;
|
||||
var a3 = f(1, a1 || "hello");
|
||||
var a4: any;
|
||||
var a4 = f(undefined, "abc");
|
||||
|
||||
function g<T>(value: [string, T]): T {
|
||||
return value[1];
|
||||
function qux(p1: Foo<void>, p2: Bar<void>) {
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
var b1: boolean;
|
||||
var b1 = g(["string", true]);
|
||||
// Repros from #32434
|
||||
|
||||
function h<T>(x: string|boolean|T): T {
|
||||
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
|
||||
}
|
||||
declare function foo<T>(x: T | Promise<T>): void;
|
||||
declare let x: false | Promise<true>;
|
||||
foo(x);
|
||||
|
||||
var c1: number;
|
||||
var c1 = h(5);
|
||||
var c2: string;
|
||||
var c2 = h("abc");
|
||||
declare function bar<T>(x: T, y: string | T): T;
|
||||
const y = bar(1, 2);
|
||||
|
||||
@@ -1,60 +1,78 @@
|
||||
//// [unionTypeInference.ts]
|
||||
// Verify that inferences made *to* a type parameter in a union type are secondary
|
||||
// to inferences made directly to that type parameter
|
||||
declare const b: boolean;
|
||||
declare const s: string;
|
||||
declare const sn: string | number;
|
||||
|
||||
function f<T>(x: T, y: string|T): T {
|
||||
return x;
|
||||
declare function f1<T>(x: T, y: string | T): T;
|
||||
|
||||
const a1 = f1(1, 2); // 1 | 2
|
||||
const a2 = f1(1, "hello"); // 1
|
||||
const a3 = f1(1, sn); // number
|
||||
const a4 = f1(undefined, "abc"); // undefined
|
||||
const a5 = f1("foo", "bar"); // "foo"
|
||||
const a6 = f1(true, false); // boolean
|
||||
const a7 = f1("hello", 1); // Error
|
||||
|
||||
declare function f2<T>(value: [string, T]): T;
|
||||
|
||||
var b1 = f2(["string", true]); // boolean
|
||||
|
||||
declare function f3<T>(x: string | false | T): T;
|
||||
|
||||
const c1 = f3(5); // 5
|
||||
const c2 = f3(sn); // number
|
||||
const c3 = f3(true); // true
|
||||
const c4 = f3(b); // true
|
||||
const c5 = f3("abc"); // never
|
||||
|
||||
declare function f4<T>(x: string & T): T;
|
||||
|
||||
const d1 = f4("abc");
|
||||
const d2 = f4(s);
|
||||
const d3 = f4(42); // Error
|
||||
|
||||
export interface Foo<T> {
|
||||
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
|
||||
}
|
||||
export interface Bar<T> {
|
||||
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
|
||||
}
|
||||
|
||||
var a1: number;
|
||||
var a1 = f(1, 2);
|
||||
var a2: number;
|
||||
var a2 = f(1, "hello");
|
||||
var a3: number;
|
||||
var a3 = f(1, a1 || "hello");
|
||||
var a4: any;
|
||||
var a4 = f(undefined, "abc");
|
||||
|
||||
function g<T>(value: [string, T]): T {
|
||||
return value[1];
|
||||
function qux(p1: Foo<void>, p2: Bar<void>) {
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
var b1: boolean;
|
||||
var b1 = g(["string", true]);
|
||||
// Repros from #32434
|
||||
|
||||
function h<T>(x: string|boolean|T): T {
|
||||
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
|
||||
}
|
||||
declare function foo<T>(x: T | Promise<T>): void;
|
||||
declare let x: false | Promise<true>;
|
||||
foo(x);
|
||||
|
||||
var c1: number;
|
||||
var c1 = h(5);
|
||||
var c2: string;
|
||||
var c2 = h("abc");
|
||||
declare function bar<T>(x: T, y: string | T): T;
|
||||
const y = bar(1, 2);
|
||||
|
||||
|
||||
//// [unionTypeInference.js]
|
||||
// Verify that inferences made *to* a type parameter in a union type are secondary
|
||||
// to inferences made directly to that type parameter
|
||||
function f(x, y) {
|
||||
return x;
|
||||
"use strict";
|
||||
exports.__esModule = true;
|
||||
var a1 = f1(1, 2); // 1 | 2
|
||||
var a2 = f1(1, "hello"); // 1
|
||||
var a3 = f1(1, sn); // number
|
||||
var a4 = f1(undefined, "abc"); // undefined
|
||||
var a5 = f1("foo", "bar"); // "foo"
|
||||
var a6 = f1(true, false); // boolean
|
||||
var a7 = f1("hello", 1); // Error
|
||||
var b1 = f2(["string", true]); // boolean
|
||||
var c1 = f3(5); // 5
|
||||
var c2 = f3(sn); // number
|
||||
var c3 = f3(true); // true
|
||||
var c4 = f3(b); // true
|
||||
var c5 = f3("abc"); // never
|
||||
var d1 = f4("abc");
|
||||
var d2 = f4(s);
|
||||
var d3 = f4(42); // Error
|
||||
function qux(p1, p2) {
|
||||
p1 = p2;
|
||||
}
|
||||
var a1;
|
||||
var a1 = f(1, 2);
|
||||
var a2;
|
||||
var a2 = f(1, "hello");
|
||||
var a3;
|
||||
var a3 = f(1, a1 || "hello");
|
||||
var a4;
|
||||
var a4 = f(undefined, "abc");
|
||||
function g(value) {
|
||||
return value[1];
|
||||
}
|
||||
var b1;
|
||||
var b1 = g(["string", true]);
|
||||
function h(x) {
|
||||
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
|
||||
}
|
||||
var c1;
|
||||
var c1 = h(5);
|
||||
var c2;
|
||||
var c2 = h("abc");
|
||||
foo(x);
|
||||
var y = bar(1, 2);
|
||||
|
||||
@@ -1,94 +1,189 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts ===
|
||||
// Verify that inferences made *to* a type parameter in a union type are secondary
|
||||
// to inferences made directly to that type parameter
|
||||
declare const b: boolean;
|
||||
>b : Symbol(b, Decl(unionTypeInference.ts, 0, 13))
|
||||
|
||||
function f<T>(x: T, y: string|T): T {
|
||||
>f : Symbol(f, Decl(unionTypeInference.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 3, 11))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 3, 14))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 3, 11))
|
||||
>y : Symbol(y, Decl(unionTypeInference.ts, 3, 19))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 3, 11))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 3, 11))
|
||||
declare const s: string;
|
||||
>s : Symbol(s, Decl(unionTypeInference.ts, 1, 13))
|
||||
|
||||
return x;
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 3, 14))
|
||||
}
|
||||
declare const sn: string | number;
|
||||
>sn : Symbol(sn, Decl(unionTypeInference.ts, 2, 13))
|
||||
|
||||
var a1: number;
|
||||
>a1 : Symbol(a1, Decl(unionTypeInference.ts, 7, 3), Decl(unionTypeInference.ts, 8, 3))
|
||||
declare function f1<T>(x: T, y: string | T): T;
|
||||
>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 4, 20))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 4, 23))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 4, 20))
|
||||
>y : Symbol(y, Decl(unionTypeInference.ts, 4, 28))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 4, 20))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 4, 20))
|
||||
|
||||
var a1 = f(1, 2);
|
||||
>a1 : Symbol(a1, Decl(unionTypeInference.ts, 7, 3), Decl(unionTypeInference.ts, 8, 3))
|
||||
>f : Symbol(f, Decl(unionTypeInference.ts, 0, 0))
|
||||
const a1 = f1(1, 2); // 1 | 2
|
||||
>a1 : Symbol(a1, Decl(unionTypeInference.ts, 6, 5))
|
||||
>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34))
|
||||
|
||||
var a2: number;
|
||||
>a2 : Symbol(a2, Decl(unionTypeInference.ts, 9, 3), Decl(unionTypeInference.ts, 10, 3))
|
||||
const a2 = f1(1, "hello"); // 1
|
||||
>a2 : Symbol(a2, Decl(unionTypeInference.ts, 7, 5))
|
||||
>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34))
|
||||
|
||||
var a2 = f(1, "hello");
|
||||
>a2 : Symbol(a2, Decl(unionTypeInference.ts, 9, 3), Decl(unionTypeInference.ts, 10, 3))
|
||||
>f : Symbol(f, Decl(unionTypeInference.ts, 0, 0))
|
||||
const a3 = f1(1, sn); // number
|
||||
>a3 : Symbol(a3, Decl(unionTypeInference.ts, 8, 5))
|
||||
>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34))
|
||||
>sn : Symbol(sn, Decl(unionTypeInference.ts, 2, 13))
|
||||
|
||||
var a3: number;
|
||||
>a3 : Symbol(a3, Decl(unionTypeInference.ts, 11, 3), Decl(unionTypeInference.ts, 12, 3))
|
||||
|
||||
var a3 = f(1, a1 || "hello");
|
||||
>a3 : Symbol(a3, Decl(unionTypeInference.ts, 11, 3), Decl(unionTypeInference.ts, 12, 3))
|
||||
>f : Symbol(f, Decl(unionTypeInference.ts, 0, 0))
|
||||
>a1 : Symbol(a1, Decl(unionTypeInference.ts, 7, 3), Decl(unionTypeInference.ts, 8, 3))
|
||||
|
||||
var a4: any;
|
||||
>a4 : Symbol(a4, Decl(unionTypeInference.ts, 13, 3), Decl(unionTypeInference.ts, 14, 3))
|
||||
|
||||
var a4 = f(undefined, "abc");
|
||||
>a4 : Symbol(a4, Decl(unionTypeInference.ts, 13, 3), Decl(unionTypeInference.ts, 14, 3))
|
||||
>f : Symbol(f, Decl(unionTypeInference.ts, 0, 0))
|
||||
const a4 = f1(undefined, "abc"); // undefined
|
||||
>a4 : Symbol(a4, Decl(unionTypeInference.ts, 9, 5))
|
||||
>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
function g<T>(value: [string, T]): T {
|
||||
>g : Symbol(g, Decl(unionTypeInference.ts, 14, 29))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 16, 11))
|
||||
>value : Symbol(value, Decl(unionTypeInference.ts, 16, 14))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 16, 11))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 16, 11))
|
||||
const a5 = f1("foo", "bar"); // "foo"
|
||||
>a5 : Symbol(a5, Decl(unionTypeInference.ts, 10, 5))
|
||||
>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34))
|
||||
|
||||
return value[1];
|
||||
>value : Symbol(value, Decl(unionTypeInference.ts, 16, 14))
|
||||
>1 : Symbol(1)
|
||||
const a6 = f1(true, false); // boolean
|
||||
>a6 : Symbol(a6, Decl(unionTypeInference.ts, 11, 5))
|
||||
>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34))
|
||||
|
||||
const a7 = f1("hello", 1); // Error
|
||||
>a7 : Symbol(a7, Decl(unionTypeInference.ts, 12, 5))
|
||||
>f1 : Symbol(f1, Decl(unionTypeInference.ts, 2, 34))
|
||||
|
||||
declare function f2<T>(value: [string, T]): T;
|
||||
>f2 : Symbol(f2, Decl(unionTypeInference.ts, 12, 26))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 14, 20))
|
||||
>value : Symbol(value, Decl(unionTypeInference.ts, 14, 23))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 14, 20))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 14, 20))
|
||||
|
||||
var b1 = f2(["string", true]); // boolean
|
||||
>b1 : Symbol(b1, Decl(unionTypeInference.ts, 16, 3))
|
||||
>f2 : Symbol(f2, Decl(unionTypeInference.ts, 12, 26))
|
||||
|
||||
declare function f3<T>(x: string | false | T): T;
|
||||
>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 18, 20))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 18, 23))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 18, 20))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 18, 20))
|
||||
|
||||
const c1 = f3(5); // 5
|
||||
>c1 : Symbol(c1, Decl(unionTypeInference.ts, 20, 5))
|
||||
>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30))
|
||||
|
||||
const c2 = f3(sn); // number
|
||||
>c2 : Symbol(c2, Decl(unionTypeInference.ts, 21, 5))
|
||||
>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30))
|
||||
>sn : Symbol(sn, Decl(unionTypeInference.ts, 2, 13))
|
||||
|
||||
const c3 = f3(true); // true
|
||||
>c3 : Symbol(c3, Decl(unionTypeInference.ts, 22, 5))
|
||||
>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30))
|
||||
|
||||
const c4 = f3(b); // true
|
||||
>c4 : Symbol(c4, Decl(unionTypeInference.ts, 23, 5))
|
||||
>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30))
|
||||
>b : Symbol(b, Decl(unionTypeInference.ts, 0, 13))
|
||||
|
||||
const c5 = f3("abc"); // never
|
||||
>c5 : Symbol(c5, Decl(unionTypeInference.ts, 24, 5))
|
||||
>f3 : Symbol(f3, Decl(unionTypeInference.ts, 16, 30))
|
||||
|
||||
declare function f4<T>(x: string & T): T;
|
||||
>f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 26, 20))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 26, 23))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 26, 20))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 26, 20))
|
||||
|
||||
const d1 = f4("abc");
|
||||
>d1 : Symbol(d1, Decl(unionTypeInference.ts, 28, 5))
|
||||
>f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21))
|
||||
|
||||
const d2 = f4(s);
|
||||
>d2 : Symbol(d2, Decl(unionTypeInference.ts, 29, 5))
|
||||
>f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21))
|
||||
>s : Symbol(s, Decl(unionTypeInference.ts, 1, 13))
|
||||
|
||||
const d3 = f4(42); // Error
|
||||
>d3 : Symbol(d3, Decl(unionTypeInference.ts, 30, 5))
|
||||
>f4 : Symbol(f4, Decl(unionTypeInference.ts, 24, 21))
|
||||
|
||||
export interface Foo<T> {
|
||||
>Foo : Symbol(Foo, Decl(unionTypeInference.ts, 30, 18))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 32, 21))
|
||||
|
||||
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
|
||||
>then : Symbol(Foo.then, Decl(unionTypeInference.ts, 32, 25))
|
||||
>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9))
|
||||
>f : Symbol(f, Decl(unionTypeInference.ts, 33, 12))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 33, 16))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 32, 21))
|
||||
>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9))
|
||||
>Foo : Symbol(Foo, Decl(unionTypeInference.ts, 30, 18))
|
||||
>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9))
|
||||
>g : Symbol(g, Decl(unionTypeInference.ts, 33, 36))
|
||||
>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9))
|
||||
>Foo : Symbol(Foo, Decl(unionTypeInference.ts, 30, 18))
|
||||
>U : Symbol(U, Decl(unionTypeInference.ts, 33, 9))
|
||||
}
|
||||
export interface Bar<T> {
|
||||
>Bar : Symbol(Bar, Decl(unionTypeInference.ts, 34, 1))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 35, 21))
|
||||
|
||||
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
|
||||
>then : Symbol(Bar.then, Decl(unionTypeInference.ts, 35, 25))
|
||||
>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9))
|
||||
>f : Symbol(f, Decl(unionTypeInference.ts, 36, 12))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 36, 16))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 35, 21))
|
||||
>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9))
|
||||
>Bar : Symbol(Bar, Decl(unionTypeInference.ts, 34, 1))
|
||||
>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9))
|
||||
>g : Symbol(g, Decl(unionTypeInference.ts, 36, 36))
|
||||
>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9))
|
||||
>Bar : Symbol(Bar, Decl(unionTypeInference.ts, 34, 1))
|
||||
>S : Symbol(S, Decl(unionTypeInference.ts, 36, 9))
|
||||
}
|
||||
|
||||
var b1: boolean;
|
||||
>b1 : Symbol(b1, Decl(unionTypeInference.ts, 20, 3), Decl(unionTypeInference.ts, 21, 3))
|
||||
function qux(p1: Foo<void>, p2: Bar<void>) {
|
||||
>qux : Symbol(qux, Decl(unionTypeInference.ts, 37, 1))
|
||||
>p1 : Symbol(p1, Decl(unionTypeInference.ts, 39, 13))
|
||||
>Foo : Symbol(Foo, Decl(unionTypeInference.ts, 30, 18))
|
||||
>p2 : Symbol(p2, Decl(unionTypeInference.ts, 39, 27))
|
||||
>Bar : Symbol(Bar, Decl(unionTypeInference.ts, 34, 1))
|
||||
|
||||
var b1 = g(["string", true]);
|
||||
>b1 : Symbol(b1, Decl(unionTypeInference.ts, 20, 3), Decl(unionTypeInference.ts, 21, 3))
|
||||
>g : Symbol(g, Decl(unionTypeInference.ts, 14, 29))
|
||||
|
||||
function h<T>(x: string|boolean|T): T {
|
||||
>h : Symbol(h, Decl(unionTypeInference.ts, 21, 29))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 23, 11))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 23, 14))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 23, 11))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 23, 11))
|
||||
|
||||
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 23, 14))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 23, 14))
|
||||
>undefined : Symbol(undefined)
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 23, 14))
|
||||
p1 = p2;
|
||||
>p1 : Symbol(p1, Decl(unionTypeInference.ts, 39, 13))
|
||||
>p2 : Symbol(p2, Decl(unionTypeInference.ts, 39, 27))
|
||||
}
|
||||
|
||||
var c1: number;
|
||||
>c1 : Symbol(c1, Decl(unionTypeInference.ts, 27, 3), Decl(unionTypeInference.ts, 28, 3))
|
||||
// Repros from #32434
|
||||
|
||||
var c1 = h(5);
|
||||
>c1 : Symbol(c1, Decl(unionTypeInference.ts, 27, 3), Decl(unionTypeInference.ts, 28, 3))
|
||||
>h : Symbol(h, Decl(unionTypeInference.ts, 21, 29))
|
||||
declare function foo<T>(x: T | Promise<T>): void;
|
||||
>foo : Symbol(foo, Decl(unionTypeInference.ts, 41, 1))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 45, 21))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 45, 24))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 45, 21))
|
||||
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 45, 21))
|
||||
|
||||
var c2: string;
|
||||
>c2 : Symbol(c2, Decl(unionTypeInference.ts, 29, 3), Decl(unionTypeInference.ts, 30, 3))
|
||||
declare let x: false | Promise<true>;
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 46, 11))
|
||||
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
var c2 = h("abc");
|
||||
>c2 : Symbol(c2, Decl(unionTypeInference.ts, 29, 3), Decl(unionTypeInference.ts, 30, 3))
|
||||
>h : Symbol(h, Decl(unionTypeInference.ts, 21, 29))
|
||||
foo(x);
|
||||
>foo : Symbol(foo, Decl(unionTypeInference.ts, 41, 1))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 46, 11))
|
||||
|
||||
declare function bar<T>(x: T, y: string | T): T;
|
||||
>bar : Symbol(bar, Decl(unionTypeInference.ts, 47, 7))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 49, 21))
|
||||
>x : Symbol(x, Decl(unionTypeInference.ts, 49, 24))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 49, 21))
|
||||
>y : Symbol(y, Decl(unionTypeInference.ts, 49, 29))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 49, 21))
|
||||
>T : Symbol(T, Decl(unionTypeInference.ts, 49, 21))
|
||||
|
||||
const y = bar(1, 2);
|
||||
>y : Symbol(y, Decl(unionTypeInference.ts, 50, 5))
|
||||
>bar : Symbol(bar, Decl(unionTypeInference.ts, 47, 7))
|
||||
|
||||
|
||||
@@ -1,113 +1,187 @@
|
||||
=== tests/cases/conformance/types/typeRelationships/typeInference/unionTypeInference.ts ===
|
||||
// Verify that inferences made *to* a type parameter in a union type are secondary
|
||||
// to inferences made directly to that type parameter
|
||||
declare const b: boolean;
|
||||
>b : boolean
|
||||
|
||||
function f<T>(x: T, y: string|T): T {
|
||||
>f : <T>(x: T, y: string | T) => T
|
||||
declare const s: string;
|
||||
>s : string
|
||||
|
||||
declare const sn: string | number;
|
||||
>sn : string | number
|
||||
|
||||
declare function f1<T>(x: T, y: string | T): T;
|
||||
>f1 : <T>(x: T, y: string | T) => T
|
||||
>x : T
|
||||
>y : string | T
|
||||
|
||||
return x;
|
||||
>x : T
|
||||
}
|
||||
|
||||
var a1: number;
|
||||
>a1 : number
|
||||
|
||||
var a1 = f(1, 2);
|
||||
>a1 : number
|
||||
>f(1, 2) : any
|
||||
>f : <T>(x: T, y: string | T) => T
|
||||
const a1 = f1(1, 2); // 1 | 2
|
||||
>a1 : 1 | 2
|
||||
>f1(1, 2) : 1 | 2
|
||||
>f1 : <T>(x: T, y: string | T) => T
|
||||
>1 : 1
|
||||
>2 : 2
|
||||
|
||||
var a2: number;
|
||||
>a2 : number
|
||||
|
||||
var a2 = f(1, "hello");
|
||||
>a2 : number
|
||||
>f(1, "hello") : 1
|
||||
>f : <T>(x: T, y: string | T) => T
|
||||
const a2 = f1(1, "hello"); // 1
|
||||
>a2 : 1
|
||||
>f1(1, "hello") : 1
|
||||
>f1 : <T>(x: T, y: string | T) => T
|
||||
>1 : 1
|
||||
>"hello" : "hello"
|
||||
|
||||
var a3: number;
|
||||
const a3 = f1(1, sn); // number
|
||||
>a3 : number
|
||||
|
||||
var a3 = f(1, a1 || "hello");
|
||||
>a3 : number
|
||||
>f(1, a1 || "hello") : number
|
||||
>f : <T>(x: T, y: string | T) => T
|
||||
>f1(1, sn) : number
|
||||
>f1 : <T>(x: T, y: string | T) => T
|
||||
>1 : 1
|
||||
>a1 || "hello" : number | "hello"
|
||||
>a1 : number
|
||||
>"hello" : "hello"
|
||||
>sn : string | number
|
||||
|
||||
var a4: any;
|
||||
>a4 : any
|
||||
|
||||
var a4 = f(undefined, "abc");
|
||||
>a4 : any
|
||||
>f(undefined, "abc") : any
|
||||
>f : <T>(x: T, y: string | T) => T
|
||||
const a4 = f1(undefined, "abc"); // undefined
|
||||
>a4 : undefined
|
||||
>f1(undefined, "abc") : undefined
|
||||
>f1 : <T>(x: T, y: string | T) => T
|
||||
>undefined : undefined
|
||||
>"abc" : "abc"
|
||||
|
||||
function g<T>(value: [string, T]): T {
|
||||
>g : <T>(value: [string, T]) => T
|
||||
>value : [string, T]
|
||||
const a5 = f1("foo", "bar"); // "foo"
|
||||
>a5 : "foo"
|
||||
>f1("foo", "bar") : "foo"
|
||||
>f1 : <T>(x: T, y: string | T) => T
|
||||
>"foo" : "foo"
|
||||
>"bar" : "bar"
|
||||
|
||||
return value[1];
|
||||
>value[1] : T
|
||||
>value : [string, T]
|
||||
const a6 = f1(true, false); // boolean
|
||||
>a6 : boolean
|
||||
>f1(true, false) : boolean
|
||||
>f1 : <T>(x: T, y: string | T) => T
|
||||
>true : true
|
||||
>false : false
|
||||
|
||||
const a7 = f1("hello", 1); // Error
|
||||
>a7 : any
|
||||
>f1("hello", 1) : any
|
||||
>f1 : <T>(x: T, y: string | T) => T
|
||||
>"hello" : "hello"
|
||||
>1 : 1
|
||||
}
|
||||
|
||||
var b1: boolean;
|
||||
>b1 : boolean
|
||||
declare function f2<T>(value: [string, T]): T;
|
||||
>f2 : <T>(value: [string, T]) => T
|
||||
>value : [string, T]
|
||||
|
||||
var b1 = g(["string", true]);
|
||||
var b1 = f2(["string", true]); // boolean
|
||||
>b1 : boolean
|
||||
>g(["string", true]) : boolean
|
||||
>g : <T>(value: [string, T]) => T
|
||||
>f2(["string", true]) : boolean
|
||||
>f2 : <T>(value: [string, T]) => T
|
||||
>["string", true] : [string, true]
|
||||
>"string" : "string"
|
||||
>true : true
|
||||
|
||||
function h<T>(x: string|boolean|T): T {
|
||||
>h : <T>(x: string | boolean | T) => T
|
||||
>x : string | boolean | T
|
||||
declare function f3<T>(x: string | false | T): T;
|
||||
>f3 : <T>(x: string | false | T) => T
|
||||
>x : string | false | T
|
||||
>false : false
|
||||
|
||||
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
|
||||
>typeof x === "string" || typeof x === "boolean" ? undefined : x : T
|
||||
>typeof x === "string" || typeof x === "boolean" : boolean
|
||||
>typeof x === "string" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : string | boolean | T
|
||||
>"string" : "string"
|
||||
>typeof x === "boolean" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : boolean | T
|
||||
>"boolean" : "boolean"
|
||||
>undefined : undefined
|
||||
>x : T
|
||||
}
|
||||
|
||||
var c1: number;
|
||||
>c1 : number
|
||||
|
||||
var c1 = h(5);
|
||||
>c1 : number
|
||||
>h(5) : 5
|
||||
>h : <T>(x: string | boolean | T) => T
|
||||
const c1 = f3(5); // 5
|
||||
>c1 : 5
|
||||
>f3(5) : 5
|
||||
>f3 : <T>(x: string | false | T) => T
|
||||
>5 : 5
|
||||
|
||||
var c2: string;
|
||||
>c2 : string
|
||||
const c2 = f3(sn); // number
|
||||
>c2 : number
|
||||
>f3(sn) : number
|
||||
>f3 : <T>(x: string | false | T) => T
|
||||
>sn : string | number
|
||||
|
||||
var c2 = h("abc");
|
||||
>c2 : string
|
||||
>h("abc") : "abc"
|
||||
>h : <T>(x: string | boolean | T) => T
|
||||
const c3 = f3(true); // true
|
||||
>c3 : true
|
||||
>f3(true) : true
|
||||
>f3 : <T>(x: string | false | T) => T
|
||||
>true : true
|
||||
|
||||
const c4 = f3(b); // true
|
||||
>c4 : true
|
||||
>f3(b) : true
|
||||
>f3 : <T>(x: string | false | T) => T
|
||||
>b : boolean
|
||||
|
||||
const c5 = f3("abc"); // never
|
||||
>c5 : unknown
|
||||
>f3("abc") : unknown
|
||||
>f3 : <T>(x: string | false | T) => T
|
||||
>"abc" : "abc"
|
||||
|
||||
declare function f4<T>(x: string & T): T;
|
||||
>f4 : <T>(x: string & T) => T
|
||||
>x : string & T
|
||||
|
||||
const d1 = f4("abc");
|
||||
>d1 : "abc"
|
||||
>f4("abc") : "abc"
|
||||
>f4 : <T>(x: string & T) => T
|
||||
>"abc" : "abc"
|
||||
|
||||
const d2 = f4(s);
|
||||
>d2 : unknown
|
||||
>f4(s) : unknown
|
||||
>f4 : <T>(x: string & T) => T
|
||||
>s : string
|
||||
|
||||
const d3 = f4(42); // Error
|
||||
>d3 : any
|
||||
>f4(42) : any
|
||||
>f4 : <T>(x: string & T) => T
|
||||
>42 : 42
|
||||
|
||||
export interface Foo<T> {
|
||||
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
|
||||
>then : <U>(f: (x: T) => U | Foo<U>, g: U) => Foo<U>
|
||||
>f : (x: T) => U | Foo<U>
|
||||
>x : T
|
||||
>g : U
|
||||
}
|
||||
export interface Bar<T> {
|
||||
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
|
||||
>then : <S>(f: (x: T) => S | Bar<S>, g: S) => Bar<S>
|
||||
>f : (x: T) => S | Bar<S>
|
||||
>x : T
|
||||
>g : S
|
||||
}
|
||||
|
||||
function qux(p1: Foo<void>, p2: Bar<void>) {
|
||||
>qux : (p1: Foo<void>, p2: Bar<void>) => void
|
||||
>p1 : Foo<void>
|
||||
>p2 : Bar<void>
|
||||
|
||||
p1 = p2;
|
||||
>p1 = p2 : Bar<void>
|
||||
>p1 : Foo<void>
|
||||
>p2 : Bar<void>
|
||||
}
|
||||
|
||||
// Repros from #32434
|
||||
|
||||
declare function foo<T>(x: T | Promise<T>): void;
|
||||
>foo : <T>(x: T | Promise<T>) => void
|
||||
>x : T | Promise<T>
|
||||
|
||||
declare let x: false | Promise<true>;
|
||||
>x : false | Promise<true>
|
||||
>false : false
|
||||
>true : true
|
||||
|
||||
foo(x);
|
||||
>foo(x) : void
|
||||
>foo : <T>(x: T | Promise<T>) => void
|
||||
>x : false | Promise<true>
|
||||
|
||||
declare function bar<T>(x: T, y: string | T): T;
|
||||
>bar : <T>(x: T, y: string | T) => T
|
||||
>x : T
|
||||
>y : string | T
|
||||
|
||||
const y = bar(1, 2);
|
||||
>y : 1 | 2
|
||||
>bar(1, 2) : 1 | 2
|
||||
>bar : <T>(x: T, y: string | T) => T
|
||||
>1 : 1
|
||||
>2 : 2
|
||||
|
||||
|
||||
@@ -1,31 +1,53 @@
|
||||
// Verify that inferences made *to* a type parameter in a union type are secondary
|
||||
// to inferences made directly to that type parameter
|
||||
// @strict: true
|
||||
|
||||
function f<T>(x: T, y: string|T): T {
|
||||
return x;
|
||||
declare const b: boolean;
|
||||
declare const s: string;
|
||||
declare const sn: string | number;
|
||||
|
||||
declare function f1<T>(x: T, y: string | T): T;
|
||||
|
||||
const a1 = f1(1, 2); // 1 | 2
|
||||
const a2 = f1(1, "hello"); // 1
|
||||
const a3 = f1(1, sn); // number
|
||||
const a4 = f1(undefined, "abc"); // undefined
|
||||
const a5 = f1("foo", "bar"); // "foo"
|
||||
const a6 = f1(true, false); // boolean
|
||||
const a7 = f1("hello", 1); // Error
|
||||
|
||||
declare function f2<T>(value: [string, T]): T;
|
||||
|
||||
var b1 = f2(["string", true]); // boolean
|
||||
|
||||
declare function f3<T>(x: string | false | T): T;
|
||||
|
||||
const c1 = f3(5); // 5
|
||||
const c2 = f3(sn); // number
|
||||
const c3 = f3(true); // true
|
||||
const c4 = f3(b); // true
|
||||
const c5 = f3("abc"); // never
|
||||
|
||||
declare function f4<T>(x: string & T): T;
|
||||
|
||||
const d1 = f4("abc");
|
||||
const d2 = f4(s);
|
||||
const d3 = f4(42); // Error
|
||||
|
||||
export interface Foo<T> {
|
||||
then<U>(f: (x: T) => U | Foo<U>, g: U): Foo<U>;
|
||||
}
|
||||
export interface Bar<T> {
|
||||
then<S>(f: (x: T) => S | Bar<S>, g: S): Bar<S>;
|
||||
}
|
||||
|
||||
var a1: number;
|
||||
var a1 = f(1, 2);
|
||||
var a2: number;
|
||||
var a2 = f(1, "hello");
|
||||
var a3: number;
|
||||
var a3 = f(1, a1 || "hello");
|
||||
var a4: any;
|
||||
var a4 = f(undefined, "abc");
|
||||
|
||||
function g<T>(value: [string, T]): T {
|
||||
return value[1];
|
||||
function qux(p1: Foo<void>, p2: Bar<void>) {
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
var b1: boolean;
|
||||
var b1 = g(["string", true]);
|
||||
// Repros from #32434
|
||||
|
||||
function h<T>(x: string|boolean|T): T {
|
||||
return typeof x === "string" || typeof x === "boolean" ? undefined : x;
|
||||
}
|
||||
declare function foo<T>(x: T | Promise<T>): void;
|
||||
declare let x: false | Promise<true>;
|
||||
foo(x);
|
||||
|
||||
var c1: number;
|
||||
var c1 = h(5);
|
||||
var c2: string;
|
||||
var c2 = h("abc");
|
||||
declare function bar<T>(x: T, y: string | T): T;
|
||||
const y = bar(1, 2);
|
||||
|
||||
Reference in New Issue
Block a user