mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Properly handle null and undefined in getCommonSupertype (#50021)
* Properly handle null and undefined in getCommonSupertype * Add tests * Add more tests
This commit is contained in:
@@ -21198,39 +21198,35 @@ namespace ts {
|
||||
function literalTypesWithSameBaseType(types: Type[]): boolean {
|
||||
let commonBaseType: Type | undefined;
|
||||
for (const t of types) {
|
||||
const baseType = getBaseTypeOfLiteralType(t);
|
||||
if (!commonBaseType) {
|
||||
commonBaseType = baseType;
|
||||
}
|
||||
if (baseType === t || baseType !== commonBaseType) {
|
||||
return false;
|
||||
if (!(t.flags & TypeFlags.Never)) {
|
||||
const baseType = getBaseTypeOfLiteralType(t);
|
||||
commonBaseType ??= baseType;
|
||||
if (baseType === t || baseType !== commonBaseType) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// When the candidate types are all literal types with the same base type, return a union
|
||||
// of those literal types. Otherwise, return the leftmost type for which no type to the
|
||||
// right is a supertype.
|
||||
function getSupertypeOrUnion(types: Type[]): Type {
|
||||
if (types.length === 1) {
|
||||
return types[0];
|
||||
}
|
||||
return literalTypesWithSameBaseType(types) ?
|
||||
getUnionType(types) :
|
||||
reduceLeft(types, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!;
|
||||
function getCombinedTypeFlags(types: Type[]): TypeFlags {
|
||||
return reduceLeft(types, (flags, t) => flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), 0);
|
||||
}
|
||||
|
||||
function getCommonSupertype(types: Type[]): Type {
|
||||
if (!strictNullChecks) {
|
||||
return getSupertypeOrUnion(types);
|
||||
if (types.length === 1) {
|
||||
return types[0];
|
||||
}
|
||||
const primaryTypes = filter(types, t => !(t.flags & TypeFlags.Nullable));
|
||||
if (primaryTypes.length) {
|
||||
const supertypeOrUnion = getSupertypeOrUnion(primaryTypes);
|
||||
return primaryTypes === types ? supertypeOrUnion : getUnionType([supertypeOrUnion, ...filter(types, t => !!(t.flags & TypeFlags.Nullable))]);
|
||||
}
|
||||
return getUnionType(types, UnionReduction.Subtype);
|
||||
// Remove nullable types from each of the candidates.
|
||||
const primaryTypes = strictNullChecks ? sameMap(types, t => filterType(t, u => !(u.flags & TypeFlags.Nullable))) : types;
|
||||
// When the candidate types are all literal types with the same base type, return a union
|
||||
// of those literal types. Otherwise, return the leftmost type for which no type to the
|
||||
// right is a supertype.
|
||||
const superTypeOrUnion = literalTypesWithSameBaseType(primaryTypes) ?
|
||||
getUnionType(primaryTypes) :
|
||||
reduceLeft(primaryTypes, (s, t) => isTypeSubtypeOf(s, t) ? t : s)!;
|
||||
// Add any nullable types that occurred in the candidates back to the result.
|
||||
return primaryTypes === types ? superTypeOrUnion : getNullableType(superTypeOrUnion, getCombinedTypeFlags(types) & TypeFlags.Nullable);
|
||||
}
|
||||
|
||||
// Return the leftmost type for which no type to the right is a subtype.
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
//// [inferenceDoesNotAddUndefinedOrNull.ts]
|
||||
interface NodeArray<T extends Node> extends ReadonlyArray<T> {}
|
||||
|
||||
interface Node {
|
||||
forEachChild<T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray<Node>) => T | undefined): T | undefined;
|
||||
}
|
||||
|
||||
declare function toArray<T>(value: T | T[]): T[];
|
||||
declare function toArray<T>(value: T | readonly T[]): readonly T[];
|
||||
|
||||
function flatMapChildren<T>(node: Node, cb: (child: Node) => readonly T[] | T | undefined): readonly T[] {
|
||||
const result: T[] = [];
|
||||
node.forEachChild(child => {
|
||||
const value = cb(child);
|
||||
if (value !== undefined) {
|
||||
result.push(...toArray(value));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function flatMapChildren2<T>(node: Node, cb: (child: Node) => readonly T[] | T | null): readonly T[] {
|
||||
const result: T[] = [];
|
||||
node.forEachChild(child => {
|
||||
const value = cb(child);
|
||||
if (value !== null) {
|
||||
result.push(...toArray(value));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
//// [inferenceDoesNotAddUndefinedOrNull.js]
|
||||
"use strict";
|
||||
function flatMapChildren(node, cb) {
|
||||
var result = [];
|
||||
node.forEachChild(function (child) {
|
||||
var value = cb(child);
|
||||
if (value !== undefined) {
|
||||
result.push.apply(result, toArray(value));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
function flatMapChildren2(node, cb) {
|
||||
var result = [];
|
||||
node.forEachChild(function (child) {
|
||||
var value = cb(child);
|
||||
if (value !== null) {
|
||||
result.push.apply(result, toArray(value));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
=== tests/cases/compiler/inferenceDoesNotAddUndefinedOrNull.ts ===
|
||||
interface NodeArray<T extends Node> extends ReadonlyArray<T> {}
|
||||
>NodeArray : Symbol(NodeArray, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 20))
|
||||
>Node : Symbol(Node, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 63))
|
||||
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 20))
|
||||
|
||||
interface Node {
|
||||
>Node : Symbol(Node, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 63))
|
||||
|
||||
forEachChild<T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray<Node>) => T | undefined): T | undefined;
|
||||
>forEachChild : Symbol(Node.forEachChild, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 2, 16))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 3, 17))
|
||||
>cbNode : Symbol(cbNode, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 3, 20))
|
||||
>node : Symbol(node, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 3, 29))
|
||||
>Node : Symbol(Node, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 63))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 3, 17))
|
||||
>cbNodeArray : Symbol(cbNodeArray, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 3, 58))
|
||||
>nodes : Symbol(nodes, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 3, 74))
|
||||
>NodeArray : Symbol(NodeArray, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 0))
|
||||
>Node : Symbol(Node, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 63))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 3, 17))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 3, 17))
|
||||
}
|
||||
|
||||
declare function toArray<T>(value: T | T[]): T[];
|
||||
>toArray : Symbol(toArray, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 4, 1), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 49))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 25))
|
||||
>value : Symbol(value, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 28))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 25))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 25))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 25))
|
||||
|
||||
declare function toArray<T>(value: T | readonly T[]): readonly T[];
|
||||
>toArray : Symbol(toArray, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 4, 1), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 49))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 7, 25))
|
||||
>value : Symbol(value, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 7, 28))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 7, 25))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 7, 25))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 7, 25))
|
||||
|
||||
function flatMapChildren<T>(node: Node, cb: (child: Node) => readonly T[] | T | undefined): readonly T[] {
|
||||
>flatMapChildren : Symbol(flatMapChildren, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 7, 67))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 25))
|
||||
>node : Symbol(node, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 28))
|
||||
>Node : Symbol(Node, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 63))
|
||||
>cb : Symbol(cb, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 39))
|
||||
>child : Symbol(child, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 45))
|
||||
>Node : Symbol(Node, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 63))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 25))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 25))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 25))
|
||||
|
||||
const result: T[] = [];
|
||||
>result : Symbol(result, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 10, 9))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 25))
|
||||
|
||||
node.forEachChild(child => {
|
||||
>node.forEachChild : Symbol(Node.forEachChild, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 2, 16))
|
||||
>node : Symbol(node, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 28))
|
||||
>forEachChild : Symbol(Node.forEachChild, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 2, 16))
|
||||
>child : Symbol(child, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 11, 22))
|
||||
|
||||
const value = cb(child);
|
||||
>value : Symbol(value, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 12, 13))
|
||||
>cb : Symbol(cb, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 9, 39))
|
||||
>child : Symbol(child, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 11, 22))
|
||||
|
||||
if (value !== undefined) {
|
||||
>value : Symbol(value, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 12, 13))
|
||||
>undefined : Symbol(undefined)
|
||||
|
||||
result.push(...toArray(value));
|
||||
>result.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
|
||||
>result : Symbol(result, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 10, 9))
|
||||
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
|
||||
>toArray : Symbol(toArray, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 4, 1), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 49))
|
||||
>value : Symbol(value, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 12, 13))
|
||||
}
|
||||
});
|
||||
return result;
|
||||
>result : Symbol(result, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 10, 9))
|
||||
}
|
||||
|
||||
function flatMapChildren2<T>(node: Node, cb: (child: Node) => readonly T[] | T | null): readonly T[] {
|
||||
>flatMapChildren2 : Symbol(flatMapChildren2, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 18, 1))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 26))
|
||||
>node : Symbol(node, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 29))
|
||||
>Node : Symbol(Node, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 63))
|
||||
>cb : Symbol(cb, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 40))
|
||||
>child : Symbol(child, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 46))
|
||||
>Node : Symbol(Node, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 0, 63))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 26))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 26))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 26))
|
||||
|
||||
const result: T[] = [];
|
||||
>result : Symbol(result, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 21, 9))
|
||||
>T : Symbol(T, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 26))
|
||||
|
||||
node.forEachChild(child => {
|
||||
>node.forEachChild : Symbol(Node.forEachChild, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 2, 16))
|
||||
>node : Symbol(node, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 29))
|
||||
>forEachChild : Symbol(Node.forEachChild, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 2, 16))
|
||||
>child : Symbol(child, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 22, 22))
|
||||
|
||||
const value = cb(child);
|
||||
>value : Symbol(value, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 23, 13))
|
||||
>cb : Symbol(cb, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 20, 40))
|
||||
>child : Symbol(child, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 22, 22))
|
||||
|
||||
if (value !== null) {
|
||||
>value : Symbol(value, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 23, 13))
|
||||
|
||||
result.push(...toArray(value));
|
||||
>result.push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
|
||||
>result : Symbol(result, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 21, 9))
|
||||
>push : Symbol(Array.push, Decl(lib.es5.d.ts, --, --))
|
||||
>toArray : Symbol(toArray, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 4, 1), Decl(inferenceDoesNotAddUndefinedOrNull.ts, 6, 49))
|
||||
>value : Symbol(value, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 23, 13))
|
||||
}
|
||||
});
|
||||
return result;
|
||||
>result : Symbol(result, Decl(inferenceDoesNotAddUndefinedOrNull.ts, 21, 9))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
=== tests/cases/compiler/inferenceDoesNotAddUndefinedOrNull.ts ===
|
||||
interface NodeArray<T extends Node> extends ReadonlyArray<T> {}
|
||||
|
||||
interface Node {
|
||||
forEachChild<T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray<Node>) => T | undefined): T | undefined;
|
||||
>forEachChild : <T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T | undefined) | undefined) => T | undefined
|
||||
>cbNode : (node: Node) => T | undefined
|
||||
>node : Node
|
||||
>cbNodeArray : ((nodes: NodeArray<Node>) => T | undefined) | undefined
|
||||
>nodes : NodeArray<Node>
|
||||
}
|
||||
|
||||
declare function toArray<T>(value: T | T[]): T[];
|
||||
>toArray : { <T>(value: T | T[]): T[]; <T>(value: T | readonly T[]): readonly T[]; }
|
||||
>value : T | T[]
|
||||
|
||||
declare function toArray<T>(value: T | readonly T[]): readonly T[];
|
||||
>toArray : { <T>(value: T | T[]): T[]; <T>(value: T | readonly T[]): readonly T[]; }
|
||||
>value : T | readonly T[]
|
||||
|
||||
function flatMapChildren<T>(node: Node, cb: (child: Node) => readonly T[] | T | undefined): readonly T[] {
|
||||
>flatMapChildren : <T>(node: Node, cb: (child: Node) => readonly T[] | T | undefined) => readonly T[]
|
||||
>node : Node
|
||||
>cb : (child: Node) => readonly T[] | T | undefined
|
||||
>child : Node
|
||||
|
||||
const result: T[] = [];
|
||||
>result : T[]
|
||||
>[] : never[]
|
||||
|
||||
node.forEachChild(child => {
|
||||
>node.forEachChild(child => { const value = cb(child); if (value !== undefined) { result.push(...toArray(value)); } }) : void | undefined
|
||||
>node.forEachChild : <T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T | undefined) | undefined) => T | undefined
|
||||
>node : Node
|
||||
>forEachChild : <T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T | undefined) | undefined) => T | undefined
|
||||
>child => { const value = cb(child); if (value !== undefined) { result.push(...toArray(value)); } } : (child: Node) => void
|
||||
>child : Node
|
||||
|
||||
const value = cb(child);
|
||||
>value : T | readonly T[] | undefined
|
||||
>cb(child) : T | readonly T[] | undefined
|
||||
>cb : (child: Node) => T | readonly T[] | undefined
|
||||
>child : Node
|
||||
|
||||
if (value !== undefined) {
|
||||
>value !== undefined : boolean
|
||||
>value : T | readonly T[] | undefined
|
||||
>undefined : undefined
|
||||
|
||||
result.push(...toArray(value));
|
||||
>result.push(...toArray(value)) : number
|
||||
>result.push : (...items: T[]) => number
|
||||
>result : T[]
|
||||
>push : (...items: T[]) => number
|
||||
>...toArray(value) : T
|
||||
>toArray(value) : readonly T[]
|
||||
>toArray : { <T>(value: T | T[]): T[]; <T>(value: T | readonly T[]): readonly T[]; }
|
||||
>value : readonly T[] | (T & ({} | null))
|
||||
}
|
||||
});
|
||||
return result;
|
||||
>result : T[]
|
||||
}
|
||||
|
||||
function flatMapChildren2<T>(node: Node, cb: (child: Node) => readonly T[] | T | null): readonly T[] {
|
||||
>flatMapChildren2 : <T>(node: Node, cb: (child: Node) => readonly T[] | T | null) => readonly T[]
|
||||
>node : Node
|
||||
>cb : (child: Node) => readonly T[] | T | null
|
||||
>child : Node
|
||||
>null : null
|
||||
|
||||
const result: T[] = [];
|
||||
>result : T[]
|
||||
>[] : never[]
|
||||
|
||||
node.forEachChild(child => {
|
||||
>node.forEachChild(child => { const value = cb(child); if (value !== null) { result.push(...toArray(value)); } }) : void | undefined
|
||||
>node.forEachChild : <T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T | undefined) | undefined) => T | undefined
|
||||
>node : Node
|
||||
>forEachChild : <T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: ((nodes: NodeArray<Node>) => T | undefined) | undefined) => T | undefined
|
||||
>child => { const value = cb(child); if (value !== null) { result.push(...toArray(value)); } } : (child: Node) => void
|
||||
>child : Node
|
||||
|
||||
const value = cb(child);
|
||||
>value : T | readonly T[] | null
|
||||
>cb(child) : T | readonly T[] | null
|
||||
>cb : (child: Node) => T | readonly T[] | null
|
||||
>child : Node
|
||||
|
||||
if (value !== null) {
|
||||
>value !== null : boolean
|
||||
>value : T | readonly T[] | null
|
||||
>null : null
|
||||
|
||||
result.push(...toArray(value));
|
||||
>result.push(...toArray(value)) : number
|
||||
>result.push : (...items: T[]) => number
|
||||
>result : T[]
|
||||
>push : (...items: T[]) => number
|
||||
>...toArray(value) : T
|
||||
>toArray(value) : readonly T[]
|
||||
>toArray : { <T>(value: T | T[]): T[]; <T>(value: T | readonly T[]): readonly T[]; }
|
||||
>value : readonly T[] | (T & ({} | undefined))
|
||||
}
|
||||
});
|
||||
return result;
|
||||
>result : T[]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
//// [inferenceOfNullableObjectTypesWithCommonBase.ts]
|
||||
function equal<T>(a: T, b: T) { }
|
||||
|
||||
let v = null!;
|
||||
|
||||
// Object types with common base types
|
||||
|
||||
type B = { foo: string }
|
||||
type D = { foo: string; bar: number }
|
||||
|
||||
equal(v as B, v as undefined | D)
|
||||
equal(v as undefined | D, v as B)
|
||||
|
||||
equal<undefined | B>(v as B, v as undefined | D)
|
||||
equal<undefined | B>(v as undefined | D, v as B)
|
||||
|
||||
equal(v as B, v as undefined)
|
||||
equal(v as undefined, v as B)
|
||||
|
||||
equal(v as B, v as D)
|
||||
equal(v as D, v as B)
|
||||
|
||||
equal(v as B, v as B | undefined)
|
||||
equal(v as B | undefined, v as B)
|
||||
|
||||
equal(v as 'a' | undefined, v as 'b');
|
||||
equal(v as 'a', v as 'b' | undefined);
|
||||
|
||||
equal(v as 'a' | undefined, v as 'b' | null);
|
||||
equal(v as 'a' | null, v as 'b' | undefined);
|
||||
|
||||
equal(v as string, v as string & { tag: 'foo' } | undefined);
|
||||
equal(v as string & { tag: 'foo' } | undefined, v as string);
|
||||
|
||||
|
||||
//// [inferenceOfNullableObjectTypesWithCommonBase.js]
|
||||
"use strict";
|
||||
function equal(a, b) { }
|
||||
var v = null;
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
equal(v, v);
|
||||
@@ -0,0 +1,125 @@
|
||||
=== tests/cases/compiler/inferenceOfNullableObjectTypesWithCommonBase.ts ===
|
||||
function equal<T>(a: T, b: T) { }
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 15))
|
||||
>a : Symbol(a, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 18))
|
||||
>T : Symbol(T, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 15))
|
||||
>b : Symbol(b, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 23))
|
||||
>T : Symbol(T, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 15))
|
||||
|
||||
let v = null!;
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
|
||||
// Object types with common base types
|
||||
|
||||
type B = { foo: string }
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>foo : Symbol(foo, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 6, 10))
|
||||
|
||||
type D = { foo: string; bar: number }
|
||||
>D : Symbol(D, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 6, 24))
|
||||
>foo : Symbol(foo, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 7, 10))
|
||||
>bar : Symbol(bar, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 7, 23))
|
||||
|
||||
equal(v as B, v as undefined | D)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>D : Symbol(D, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 6, 24))
|
||||
|
||||
equal(v as undefined | D, v as B)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>D : Symbol(D, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 6, 24))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
|
||||
equal<undefined | B>(v as B, v as undefined | D)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>D : Symbol(D, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 6, 24))
|
||||
|
||||
equal<undefined | B>(v as undefined | D, v as B)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>D : Symbol(D, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 6, 24))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
|
||||
equal(v as B, v as undefined)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
|
||||
equal(v as undefined, v as B)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
|
||||
equal(v as B, v as D)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>D : Symbol(D, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 6, 24))
|
||||
|
||||
equal(v as D, v as B)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>D : Symbol(D, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 6, 24))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
|
||||
equal(v as B, v as B | undefined)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
|
||||
equal(v as B | undefined, v as B)
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>B : Symbol(B, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 14))
|
||||
|
||||
equal(v as 'a' | undefined, v as 'b');
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
|
||||
equal(v as 'a', v as 'b' | undefined);
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
|
||||
equal(v as 'a' | undefined, v as 'b' | null);
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
|
||||
equal(v as 'a' | null, v as 'b' | undefined);
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
|
||||
equal(v as string, v as string & { tag: 'foo' } | undefined);
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>tag : Symbol(tag, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 30, 34))
|
||||
|
||||
equal(v as string & { tag: 'foo' } | undefined, v as string);
|
||||
>equal : Symbol(equal, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 0, 0))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
>tag : Symbol(tag, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 31, 21))
|
||||
>v : Symbol(v, Decl(inferenceOfNullableObjectTypesWithCommonBase.ts, 2, 3))
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
=== tests/cases/compiler/inferenceOfNullableObjectTypesWithCommonBase.ts ===
|
||||
function equal<T>(a: T, b: T) { }
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>a : T
|
||||
>b : T
|
||||
|
||||
let v = null!;
|
||||
>v : never
|
||||
>null! : never
|
||||
>null : null
|
||||
|
||||
// Object types with common base types
|
||||
|
||||
type B = { foo: string }
|
||||
>B : { foo: string; }
|
||||
>foo : string
|
||||
|
||||
type D = { foo: string; bar: number }
|
||||
>D : { foo: string; bar: number; }
|
||||
>foo : string
|
||||
>bar : number
|
||||
|
||||
equal(v as B, v as undefined | D)
|
||||
>equal(v as B, v as undefined | D) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as B : B
|
||||
>v : never
|
||||
>v as undefined | D : D | undefined
|
||||
>v : never
|
||||
|
||||
equal(v as undefined | D, v as B)
|
||||
>equal(v as undefined | D, v as B) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as undefined | D : D | undefined
|
||||
>v : never
|
||||
>v as B : B
|
||||
>v : never
|
||||
|
||||
equal<undefined | B>(v as B, v as undefined | D)
|
||||
>equal<undefined | B>(v as B, v as undefined | D) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as B : B
|
||||
>v : never
|
||||
>v as undefined | D : D | undefined
|
||||
>v : never
|
||||
|
||||
equal<undefined | B>(v as undefined | D, v as B)
|
||||
>equal<undefined | B>(v as undefined | D, v as B) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as undefined | D : D | undefined
|
||||
>v : never
|
||||
>v as B : B
|
||||
>v : never
|
||||
|
||||
equal(v as B, v as undefined)
|
||||
>equal(v as B, v as undefined) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as B : B
|
||||
>v : never
|
||||
>v as undefined : undefined
|
||||
>v : never
|
||||
|
||||
equal(v as undefined, v as B)
|
||||
>equal(v as undefined, v as B) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as undefined : undefined
|
||||
>v : never
|
||||
>v as B : B
|
||||
>v : never
|
||||
|
||||
equal(v as B, v as D)
|
||||
>equal(v as B, v as D) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as B : B
|
||||
>v : never
|
||||
>v as D : D
|
||||
>v : never
|
||||
|
||||
equal(v as D, v as B)
|
||||
>equal(v as D, v as B) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as D : D
|
||||
>v : never
|
||||
>v as B : B
|
||||
>v : never
|
||||
|
||||
equal(v as B, v as B | undefined)
|
||||
>equal(v as B, v as B | undefined) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as B : B
|
||||
>v : never
|
||||
>v as B | undefined : B | undefined
|
||||
>v : never
|
||||
|
||||
equal(v as B | undefined, v as B)
|
||||
>equal(v as B | undefined, v as B) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as B | undefined : B | undefined
|
||||
>v : never
|
||||
>v as B : B
|
||||
>v : never
|
||||
|
||||
equal(v as 'a' | undefined, v as 'b');
|
||||
>equal(v as 'a' | undefined, v as 'b') : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as 'a' | undefined : "a" | undefined
|
||||
>v : never
|
||||
>v as 'b' : "b"
|
||||
>v : never
|
||||
|
||||
equal(v as 'a', v as 'b' | undefined);
|
||||
>equal(v as 'a', v as 'b' | undefined) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as 'a' : "a"
|
||||
>v : never
|
||||
>v as 'b' | undefined : "b" | undefined
|
||||
>v : never
|
||||
|
||||
equal(v as 'a' | undefined, v as 'b' | null);
|
||||
>equal(v as 'a' | undefined, v as 'b' | null) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as 'a' | undefined : "a" | undefined
|
||||
>v : never
|
||||
>v as 'b' | null : "b" | null
|
||||
>v : never
|
||||
>null : null
|
||||
|
||||
equal(v as 'a' | null, v as 'b' | undefined);
|
||||
>equal(v as 'a' | null, v as 'b' | undefined) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as 'a' | null : "a" | null
|
||||
>v : never
|
||||
>null : null
|
||||
>v as 'b' | undefined : "b" | undefined
|
||||
>v : never
|
||||
|
||||
equal(v as string, v as string & { tag: 'foo' } | undefined);
|
||||
>equal(v as string, v as string & { tag: 'foo' } | undefined) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as string : string
|
||||
>v : never
|
||||
>v as string & { tag: 'foo' } | undefined : (string & { tag: 'foo'; }) | undefined
|
||||
>v : never
|
||||
>tag : "foo"
|
||||
|
||||
equal(v as string & { tag: 'foo' } | undefined, v as string);
|
||||
>equal(v as string & { tag: 'foo' } | undefined, v as string) : void
|
||||
>equal : <T>(a: T, b: T) => void
|
||||
>v as string & { tag: 'foo' } | undefined : (string & { tag: 'foo'; }) | undefined
|
||||
>v : never
|
||||
>tag : "foo"
|
||||
>v as string : string
|
||||
>v : never
|
||||
|
||||
32
tests/cases/compiler/inferenceDoesNotAddUndefinedOrNull.ts
Normal file
32
tests/cases/compiler/inferenceDoesNotAddUndefinedOrNull.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
// @strict: true
|
||||
|
||||
interface NodeArray<T extends Node> extends ReadonlyArray<T> {}
|
||||
|
||||
interface Node {
|
||||
forEachChild<T>(cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray<Node>) => T | undefined): T | undefined;
|
||||
}
|
||||
|
||||
declare function toArray<T>(value: T | T[]): T[];
|
||||
declare function toArray<T>(value: T | readonly T[]): readonly T[];
|
||||
|
||||
function flatMapChildren<T>(node: Node, cb: (child: Node) => readonly T[] | T | undefined): readonly T[] {
|
||||
const result: T[] = [];
|
||||
node.forEachChild(child => {
|
||||
const value = cb(child);
|
||||
if (value !== undefined) {
|
||||
result.push(...toArray(value));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function flatMapChildren2<T>(node: Node, cb: (child: Node) => readonly T[] | T | null): readonly T[] {
|
||||
const result: T[] = [];
|
||||
node.forEachChild(child => {
|
||||
const value = cb(child);
|
||||
if (value !== null) {
|
||||
result.push(...toArray(value));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// @strict: true
|
||||
|
||||
function equal<T>(a: T, b: T) { }
|
||||
|
||||
let v = null!;
|
||||
|
||||
// Object types with common base types
|
||||
|
||||
type B = { foo: string }
|
||||
type D = { foo: string; bar: number }
|
||||
|
||||
equal(v as B, v as undefined | D)
|
||||
equal(v as undefined | D, v as B)
|
||||
|
||||
equal<undefined | B>(v as B, v as undefined | D)
|
||||
equal<undefined | B>(v as undefined | D, v as B)
|
||||
|
||||
equal(v as B, v as undefined)
|
||||
equal(v as undefined, v as B)
|
||||
|
||||
equal(v as B, v as D)
|
||||
equal(v as D, v as B)
|
||||
|
||||
equal(v as B, v as B | undefined)
|
||||
equal(v as B | undefined, v as B)
|
||||
|
||||
equal(v as 'a' | undefined, v as 'b');
|
||||
equal(v as 'a', v as 'b' | undefined);
|
||||
|
||||
equal(v as 'a' | undefined, v as 'b' | null);
|
||||
equal(v as 'a' | null, v as 'b' | undefined);
|
||||
|
||||
equal(v as string, v as string & { tag: 'foo' } | undefined);
|
||||
equal(v as string & { tag: 'foo' } | undefined, v as string);
|
||||
Reference in New Issue
Block a user