mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Improvements to strictSubtypeRelation and getNarrowedType (#52282)
This commit is contained in:
+38
-21
@@ -1252,12 +1252,13 @@ export const enum CheckMode {
|
||||
|
||||
/** @internal */
|
||||
export const enum SignatureCheckMode {
|
||||
None = 0,
|
||||
None = 0,
|
||||
BivariantCallback = 1 << 0,
|
||||
StrictCallback = 1 << 1,
|
||||
StrictCallback = 1 << 1,
|
||||
IgnoreReturnTypes = 1 << 2,
|
||||
StrictArity = 1 << 3,
|
||||
Callback = BivariantCallback | StrictCallback,
|
||||
StrictArity = 1 << 3,
|
||||
StrictTopSignature = 1 << 4,
|
||||
Callback = BivariantCallback | StrictCallback,
|
||||
}
|
||||
|
||||
const enum IntersectionState {
|
||||
@@ -19582,12 +19583,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void;
|
||||
|
||||
/**
|
||||
* Returns true if `s` is `(...args: any[]) => any` or `(this: any, ...args: any[]) => any`
|
||||
* Returns true if `s` is `(...args: A) => R` where `A` is `any`, `any[]`, `never`, or `never[]`, and `R` is `any` or `unknown`.
|
||||
*/
|
||||
function isAnySignature(s: Signature) {
|
||||
return !s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) && s.parameters.length === 1 &&
|
||||
signatureHasRestParameter(s) && (getTypeOfParameter(s.parameters[0]) === anyArrayType || isTypeAny(getTypeOfParameter(s.parameters[0]))) &&
|
||||
isTypeAny(getReturnTypeOfSignature(s));
|
||||
function isTopSignature(s: Signature) {
|
||||
if (!s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) && s.parameters.length === 1 && signatureHasRestParameter(s)) {
|
||||
const paramType = getTypeOfParameter(s.parameters[0]);
|
||||
const restType = isArrayType(paramType) ? getTypeArguments(paramType)[0] : paramType;
|
||||
return !!(restType.flags & (TypeFlags.Any | TypeFlags.Never) && getReturnTypeOfSignature(s).flags & TypeFlags.AnyOrUnknown);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -19606,9 +19610,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return Ternary.True;
|
||||
}
|
||||
|
||||
if (isAnySignature(target)) {
|
||||
if (!(checkMode & SignatureCheckMode.StrictTopSignature && isTopSignature(source)) && isTopSignature(target)) {
|
||||
return Ternary.True;
|
||||
}
|
||||
if (checkMode & SignatureCheckMode.StrictTopSignature && isTopSignature(source) && !isTopSignature(target)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
|
||||
const targetCount = getParameterCount(target);
|
||||
const sourceHasMoreParameters = !hasEffectiveRestParameter(target) &&
|
||||
@@ -19864,7 +19871,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map<string, RelationComparisonResult>, errorReporter?: ErrorReporter) {
|
||||
const s = source.flags;
|
||||
const t = target.flags;
|
||||
if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType) return true;
|
||||
if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true;
|
||||
if (t & TypeFlags.Unknown && !(relation === strictSubtypeRelation && s & TypeFlags.Any)) return true;
|
||||
if (t & TypeFlags.Never) return false;
|
||||
if (s & TypeFlags.StringLike && t & TypeFlags.String) return true;
|
||||
if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral &&
|
||||
@@ -21486,8 +21494,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
// Consider a fresh empty object literal type "closed" under the subtype relationship - this way `{} <- {[idx: string]: any} <- fresh({})`
|
||||
// and not `{} <- fresh({}) <- {[idx: string]: any}`
|
||||
// A fresh empty object type is never a subtype of a non-empty object type. This ensures fresh({}) <: { [x: string]: xxx }
|
||||
// but not vice-versa. Without this rule, those types would be mutual subtypes.
|
||||
else if ((relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
@@ -22142,8 +22150,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
* See signatureAssignableTo, compareSignaturesIdentical
|
||||
*/
|
||||
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, intersectionState: IntersectionState, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
|
||||
const checkMode = relation === subtypeRelation ? SignatureCheckMode.StrictTopSignature :
|
||||
relation === strictSubtypeRelation ? SignatureCheckMode.StrictTopSignature | SignatureCheckMode.StrictArity :
|
||||
SignatureCheckMode.None;
|
||||
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
|
||||
relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper);
|
||||
checkMode, reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper);
|
||||
function isRelatedToWorker(source: Type, target: Type, reportErrors?: boolean) {
|
||||
return isRelatedTo(source, target, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
|
||||
}
|
||||
@@ -22239,8 +22250,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
if (sourceInfo) {
|
||||
return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors, intersectionState);
|
||||
}
|
||||
if (!(intersectionState & IntersectionState.Source) && isObjectTypeWithInferableIndex(source)) {
|
||||
// Intersection constituents are never considered to have an inferred index signature
|
||||
// Intersection constituents are never considered to have an inferred index signature. Also, in the strict subtype relation,
|
||||
// only fresh object literals are considered to have inferred index signatures. This ensures { [x: string]: xxx } <: {} but
|
||||
// not vice-versa. Without this rule, those types would be mutual strict subtypes.
|
||||
if (!(intersectionState & IntersectionState.Source) && (relation !== strictSubtypeRelation || getObjectFlags(source) & ObjectFlags.FreshLiteral) && isObjectTypeWithInferableIndex(source)) {
|
||||
return membersRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState);
|
||||
}
|
||||
if (reportErrors) {
|
||||
@@ -27089,21 +27102,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
return emptyObjectType;
|
||||
}
|
||||
|
||||
function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) {
|
||||
function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean): Type {
|
||||
const key = type.flags & TypeFlags.Union ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` : undefined;
|
||||
return getCachedType(key) ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived));
|
||||
}
|
||||
|
||||
function getNarrowedTypeWorker(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) {
|
||||
const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf;
|
||||
if (!assumeTrue) {
|
||||
return filterType(type, t => !isRelated(t, candidate));
|
||||
if (checkDerived) {
|
||||
return filterType(type, t => !isTypeDerivedFrom(t, candidate));
|
||||
}
|
||||
const trueType = getNarrowedType(type, candidate, /*assumeTrue*/ true, /*checkDerived*/ false);
|
||||
return filterType(type, t => !isTypeSubsetOf(t, trueType));
|
||||
}
|
||||
if (type.flags & TypeFlags.AnyOrUnknown) {
|
||||
return candidate;
|
||||
}
|
||||
// We first attempt to filter the current type, narrowing constituents as appropriate and removing
|
||||
// constituents that are unrelated to the candidate.
|
||||
const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf;
|
||||
const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined;
|
||||
const narrowedType = mapType(candidate, c => {
|
||||
// If a discriminant property is available, use that to reduce the type.
|
||||
@@ -27115,7 +27132,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
// prototype object types.
|
||||
const directlyRelated = mapType(matching || type, checkDerived ?
|
||||
t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType :
|
||||
t => isTypeSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : neverType);
|
||||
t => isTypeSubtypeOf(c, t) && !isTypeIdenticalTo(c, t) ? c : isTypeSubtypeOf(t, c) ? t : neverType);
|
||||
// If no constituents are directly related, create intersections for any generic constituents that
|
||||
// are related by constraint.
|
||||
return directlyRelated.flags & TypeFlags.Never ?
|
||||
@@ -36529,7 +36546,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
}
|
||||
else {
|
||||
checkAssignmentOperator(rightType);
|
||||
return getRegularTypeOfObjectLiteral(rightType);
|
||||
return rightType;
|
||||
}
|
||||
case SyntaxKind.CommaToken:
|
||||
if (!compilerOptions.allowUnreachableCode && isSideEffectFree(left) && !isIndirectCall(left.parent as BinaryExpression)) {
|
||||
|
||||
@@ -64,9 +64,9 @@ if (isNodeList(sourceObj)) {
|
||||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : Symbol(NodeList.length, Decl(controlFlowBinaryOrExpression.ts, 10, 27))
|
||||
>sourceObj.length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
>length : Symbol(NodeList.length, Decl(controlFlowBinaryOrExpression.ts, 10, 27))
|
||||
>length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
}
|
||||
|
||||
if (isHTMLCollection(sourceObj)) {
|
||||
@@ -74,9 +74,9 @@ if (isHTMLCollection(sourceObj)) {
|
||||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>sourceObj.length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>sourceObj : Symbol(sourceObj, Decl(controlFlowBinaryOrExpression.ts, 23, 3))
|
||||
>length : Symbol(HTMLCollection.length, Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
>length : Symbol(length, Decl(controlFlowBinaryOrExpression.ts, 10, 27), Decl(controlFlowBinaryOrExpression.ts, 14, 33))
|
||||
}
|
||||
|
||||
if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
|
||||
|
||||
@@ -69,18 +69,18 @@ if (isNodeList(sourceObj)) {
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : number
|
||||
>sourceObj : NodeList
|
||||
>sourceObj : NodeList | HTMLCollection
|
||||
>length : number
|
||||
}
|
||||
|
||||
if (isHTMLCollection(sourceObj)) {
|
||||
>isHTMLCollection(sourceObj) : boolean
|
||||
>isHTMLCollection : (sourceObj: any) => sourceObj is HTMLCollection
|
||||
>sourceObj : NodeList | { a: string; }
|
||||
>sourceObj : EventTargetLike
|
||||
|
||||
sourceObj.length;
|
||||
>sourceObj.length : number
|
||||
>sourceObj : HTMLCollection
|
||||
>sourceObj : NodeList | HTMLCollection
|
||||
>length : number
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
|
||||
>isNodeList(sourceObj) || isHTMLCollection(sourceObj) : boolean
|
||||
>isNodeList(sourceObj) : boolean
|
||||
>isNodeList : (sourceObj: any) => sourceObj is NodeList
|
||||
>sourceObj : HTMLCollection | { a: string; }
|
||||
>sourceObj : EventTargetLike
|
||||
>isHTMLCollection(sourceObj) : boolean
|
||||
>isHTMLCollection : (sourceObj: any) => sourceObj is HTMLCollection
|
||||
>sourceObj : { a: string; }
|
||||
|
||||
@@ -23,7 +23,7 @@ if (isObject1(obj1)) {
|
||||
}
|
||||
// check type after conditional block
|
||||
obj1;
|
||||
>obj1 : Record<string, unknown>
|
||||
>obj1 : {}
|
||||
|
||||
declare const obj2: {} | undefined;
|
||||
>obj2 : {} | undefined
|
||||
@@ -43,7 +43,7 @@ if (isObject1(obj2)) {
|
||||
}
|
||||
// check type after conditional block
|
||||
obj2;
|
||||
>obj2 : Record<string, unknown> | undefined
|
||||
>obj2 : {} | undefined
|
||||
|
||||
declare function isObject2(value: unknown): value is {};
|
||||
>isObject2 : (value: unknown) => value is {}
|
||||
@@ -67,7 +67,7 @@ if (isObject2(obj3)) {
|
||||
}
|
||||
// check type after conditional block
|
||||
obj3;
|
||||
>obj3 : {}
|
||||
>obj3 : Record<string, unknown>
|
||||
|
||||
declare const obj4: Record<string, unknown> | undefined;
|
||||
>obj4 : Record<string, unknown> | undefined
|
||||
@@ -87,5 +87,5 @@ if (isObject2(obj4)) {
|
||||
}
|
||||
// check type after conditional block
|
||||
obj4;
|
||||
>obj4 : {} | undefined
|
||||
>obj4 : Record<string, unknown> | undefined
|
||||
|
||||
|
||||
@@ -95,9 +95,9 @@ function foo2(x: C1 | C2 | C3): string {
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
|
||||
return x.item;
|
||||
>x.item : Symbol(C1.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10))
|
||||
>x.item : Symbol(item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10), Decl(instanceofWithStructurallyIdenticalTypes.ts, 4, 10))
|
||||
>x : Symbol(x, Decl(instanceofWithStructurallyIdenticalTypes.ts, 23, 14))
|
||||
>item : Symbol(C1.item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10))
|
||||
>item : Symbol(item, Decl(instanceofWithStructurallyIdenticalTypes.ts, 2, 10), Decl(instanceofWithStructurallyIdenticalTypes.ts, 4, 10))
|
||||
}
|
||||
else if (isC2(x)) {
|
||||
>isC2 : Symbol(isC2, Decl(instanceofWithStructurallyIdenticalTypes.ts, 19, 66))
|
||||
|
||||
@@ -85,7 +85,7 @@ function foo2(x: C1 | C2 | C3): string {
|
||||
|
||||
return x.item;
|
||||
>x.item : string
|
||||
>x : C1
|
||||
>x : C1 | C3
|
||||
>item : string
|
||||
}
|
||||
else if (isC2(x)) {
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
//// [narrowingMutualSubtypes.ts]
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const ru1: { [x: string]: unknown };
|
||||
declare const ra1: { [x: string]: any };
|
||||
|
||||
const a1a = [ru1, ra1]; // { [x: string]: any }[]
|
||||
const a1b = [ra1, ru1]; // { [x: string]: any }[]
|
||||
|
||||
declare const ra2: { [x: string]: any };
|
||||
declare const ru2: { [x: string]: unknown };
|
||||
|
||||
const a2a = [ru2, ra2]; // { [x: string]: any }[]
|
||||
const a2b = [ra2, ru2]; // { [x: string]: any }[]
|
||||
|
||||
// Check that `{}` is strict supertype of any non-empty object
|
||||
|
||||
const c3 = {};
|
||||
declare const r3: { [x: string]: unknown }
|
||||
|
||||
const a3a = [c3, r3]; // {}[]
|
||||
const a3b = [r3, c3]; // {}[]
|
||||
|
||||
declare const r4: { [x: string]: unknown }
|
||||
const c4 = {};
|
||||
|
||||
const a4a = [c4, r4]; // {}[]
|
||||
const a4b = [r4, c4]; // {}[]
|
||||
|
||||
// Check that narrowing preserves original type in false branch for non-identical mutual subtypes
|
||||
|
||||
declare function isObject1(value: unknown): value is Record<string, unknown>;
|
||||
|
||||
function gg(x: {}) {
|
||||
if (isObject1(x)) {
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
else {
|
||||
x; // {}
|
||||
}
|
||||
x; // {}
|
||||
}
|
||||
|
||||
declare function isObject2(value: unknown): value is {};
|
||||
|
||||
function gg2(x: Record<string, unknown>) {
|
||||
if (isObject2(x)) {
|
||||
x; // {}
|
||||
}
|
||||
else {
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
|
||||
// Repro from #50916
|
||||
|
||||
type Identity<T> = {[K in keyof T]: T[K]};
|
||||
|
||||
type Self<T> = T extends unknown ? Identity<T> : never;
|
||||
|
||||
function is<T>(value: T): value is Self<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
type Union = {a: number} | {b: number} | {c: number};
|
||||
|
||||
function example(x: Union) {
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
x; // Union
|
||||
}
|
||||
|
||||
|
||||
//// [narrowingMutualSubtypes.js]
|
||||
"use strict";
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
var a1a = [ru1, ra1]; // { [x: string]: any }[]
|
||||
var a1b = [ra1, ru1]; // { [x: string]: any }[]
|
||||
var a2a = [ru2, ra2]; // { [x: string]: any }[]
|
||||
var a2b = [ra2, ru2]; // { [x: string]: any }[]
|
||||
// Check that `{}` is strict supertype of any non-empty object
|
||||
var c3 = {};
|
||||
var a3a = [c3, r3]; // {}[]
|
||||
var a3b = [r3, c3]; // {}[]
|
||||
var c4 = {};
|
||||
var a4a = [c4, r4]; // {}[]
|
||||
var a4b = [r4, c4]; // {}[]
|
||||
function gg(x) {
|
||||
if (isObject1(x)) {
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
else {
|
||||
x; // {}
|
||||
}
|
||||
x; // {}
|
||||
}
|
||||
function gg2(x) {
|
||||
if (isObject2(x)) {
|
||||
x; // {}
|
||||
}
|
||||
else {
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
function is(value) {
|
||||
return true;
|
||||
}
|
||||
function example(x) {
|
||||
if (is(x)) { }
|
||||
if (is(x)) { }
|
||||
if (is(x)) { }
|
||||
if (is(x)) { }
|
||||
if (is(x)) { }
|
||||
if (is(x)) { }
|
||||
if (is(x)) { }
|
||||
if (is(x)) { }
|
||||
x; // Union
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
=== tests/cases/compiler/narrowingMutualSubtypes.ts ===
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const ru1: { [x: string]: unknown };
|
||||
>ru1 : Symbol(ru1, Decl(narrowingMutualSubtypes.ts, 2, 13))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 2, 22))
|
||||
|
||||
declare const ra1: { [x: string]: any };
|
||||
>ra1 : Symbol(ra1, Decl(narrowingMutualSubtypes.ts, 3, 13))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 3, 22))
|
||||
|
||||
const a1a = [ru1, ra1]; // { [x: string]: any }[]
|
||||
>a1a : Symbol(a1a, Decl(narrowingMutualSubtypes.ts, 5, 5))
|
||||
>ru1 : Symbol(ru1, Decl(narrowingMutualSubtypes.ts, 2, 13))
|
||||
>ra1 : Symbol(ra1, Decl(narrowingMutualSubtypes.ts, 3, 13))
|
||||
|
||||
const a1b = [ra1, ru1]; // { [x: string]: any }[]
|
||||
>a1b : Symbol(a1b, Decl(narrowingMutualSubtypes.ts, 6, 5))
|
||||
>ra1 : Symbol(ra1, Decl(narrowingMutualSubtypes.ts, 3, 13))
|
||||
>ru1 : Symbol(ru1, Decl(narrowingMutualSubtypes.ts, 2, 13))
|
||||
|
||||
declare const ra2: { [x: string]: any };
|
||||
>ra2 : Symbol(ra2, Decl(narrowingMutualSubtypes.ts, 8, 13))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 8, 22))
|
||||
|
||||
declare const ru2: { [x: string]: unknown };
|
||||
>ru2 : Symbol(ru2, Decl(narrowingMutualSubtypes.ts, 9, 13))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 9, 22))
|
||||
|
||||
const a2a = [ru2, ra2]; // { [x: string]: any }[]
|
||||
>a2a : Symbol(a2a, Decl(narrowingMutualSubtypes.ts, 11, 5))
|
||||
>ru2 : Symbol(ru2, Decl(narrowingMutualSubtypes.ts, 9, 13))
|
||||
>ra2 : Symbol(ra2, Decl(narrowingMutualSubtypes.ts, 8, 13))
|
||||
|
||||
const a2b = [ra2, ru2]; // { [x: string]: any }[]
|
||||
>a2b : Symbol(a2b, Decl(narrowingMutualSubtypes.ts, 12, 5))
|
||||
>ra2 : Symbol(ra2, Decl(narrowingMutualSubtypes.ts, 8, 13))
|
||||
>ru2 : Symbol(ru2, Decl(narrowingMutualSubtypes.ts, 9, 13))
|
||||
|
||||
// Check that `{}` is strict supertype of any non-empty object
|
||||
|
||||
const c3 = {};
|
||||
>c3 : Symbol(c3, Decl(narrowingMutualSubtypes.ts, 16, 5))
|
||||
|
||||
declare const r3: { [x: string]: unknown }
|
||||
>r3 : Symbol(r3, Decl(narrowingMutualSubtypes.ts, 17, 13))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 17, 21))
|
||||
|
||||
const a3a = [c3, r3]; // {}[]
|
||||
>a3a : Symbol(a3a, Decl(narrowingMutualSubtypes.ts, 19, 5))
|
||||
>c3 : Symbol(c3, Decl(narrowingMutualSubtypes.ts, 16, 5))
|
||||
>r3 : Symbol(r3, Decl(narrowingMutualSubtypes.ts, 17, 13))
|
||||
|
||||
const a3b = [r3, c3]; // {}[]
|
||||
>a3b : Symbol(a3b, Decl(narrowingMutualSubtypes.ts, 20, 5))
|
||||
>r3 : Symbol(r3, Decl(narrowingMutualSubtypes.ts, 17, 13))
|
||||
>c3 : Symbol(c3, Decl(narrowingMutualSubtypes.ts, 16, 5))
|
||||
|
||||
declare const r4: { [x: string]: unknown }
|
||||
>r4 : Symbol(r4, Decl(narrowingMutualSubtypes.ts, 22, 13))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 22, 21))
|
||||
|
||||
const c4 = {};
|
||||
>c4 : Symbol(c4, Decl(narrowingMutualSubtypes.ts, 23, 5))
|
||||
|
||||
const a4a = [c4, r4]; // {}[]
|
||||
>a4a : Symbol(a4a, Decl(narrowingMutualSubtypes.ts, 25, 5))
|
||||
>c4 : Symbol(c4, Decl(narrowingMutualSubtypes.ts, 23, 5))
|
||||
>r4 : Symbol(r4, Decl(narrowingMutualSubtypes.ts, 22, 13))
|
||||
|
||||
const a4b = [r4, c4]; // {}[]
|
||||
>a4b : Symbol(a4b, Decl(narrowingMutualSubtypes.ts, 26, 5))
|
||||
>r4 : Symbol(r4, Decl(narrowingMutualSubtypes.ts, 22, 13))
|
||||
>c4 : Symbol(c4, Decl(narrowingMutualSubtypes.ts, 23, 5))
|
||||
|
||||
// Check that narrowing preserves original type in false branch for non-identical mutual subtypes
|
||||
|
||||
declare function isObject1(value: unknown): value is Record<string, unknown>;
|
||||
>isObject1 : Symbol(isObject1, Decl(narrowingMutualSubtypes.ts, 26, 21))
|
||||
>value : Symbol(value, Decl(narrowingMutualSubtypes.ts, 30, 27))
|
||||
>value : Symbol(value, Decl(narrowingMutualSubtypes.ts, 30, 27))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
function gg(x: {}) {
|
||||
>gg : Symbol(gg, Decl(narrowingMutualSubtypes.ts, 30, 77))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 32, 12))
|
||||
|
||||
if (isObject1(x)) {
|
||||
>isObject1 : Symbol(isObject1, Decl(narrowingMutualSubtypes.ts, 26, 21))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 32, 12))
|
||||
|
||||
x; // Record<string, unknown>
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 32, 12))
|
||||
}
|
||||
else {
|
||||
x; // {}
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 32, 12))
|
||||
}
|
||||
x; // {}
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 32, 12))
|
||||
}
|
||||
|
||||
declare function isObject2(value: unknown): value is {};
|
||||
>isObject2 : Symbol(isObject2, Decl(narrowingMutualSubtypes.ts, 40, 1))
|
||||
>value : Symbol(value, Decl(narrowingMutualSubtypes.ts, 42, 27))
|
||||
>value : Symbol(value, Decl(narrowingMutualSubtypes.ts, 42, 27))
|
||||
|
||||
function gg2(x: Record<string, unknown>) {
|
||||
>gg2 : Symbol(gg2, Decl(narrowingMutualSubtypes.ts, 42, 56))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 44, 13))
|
||||
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
if (isObject2(x)) {
|
||||
>isObject2 : Symbol(isObject2, Decl(narrowingMutualSubtypes.ts, 40, 1))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 44, 13))
|
||||
|
||||
x; // {}
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 44, 13))
|
||||
}
|
||||
else {
|
||||
x; // Record<string, unknown>
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 44, 13))
|
||||
}
|
||||
x; // Record<string, unknown>
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 44, 13))
|
||||
}
|
||||
|
||||
// Repro from #50916
|
||||
|
||||
type Identity<T> = {[K in keyof T]: T[K]};
|
||||
>Identity : Symbol(Identity, Decl(narrowingMutualSubtypes.ts, 52, 1))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 56, 14))
|
||||
>K : Symbol(K, Decl(narrowingMutualSubtypes.ts, 56, 21))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 56, 14))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 56, 14))
|
||||
>K : Symbol(K, Decl(narrowingMutualSubtypes.ts, 56, 21))
|
||||
|
||||
type Self<T> = T extends unknown ? Identity<T> : never;
|
||||
>Self : Symbol(Self, Decl(narrowingMutualSubtypes.ts, 56, 42))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 58, 10))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 58, 10))
|
||||
>Identity : Symbol(Identity, Decl(narrowingMutualSubtypes.ts, 52, 1))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 58, 10))
|
||||
|
||||
function is<T>(value: T): value is Self<T> {
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 60, 12))
|
||||
>value : Symbol(value, Decl(narrowingMutualSubtypes.ts, 60, 15))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 60, 12))
|
||||
>value : Symbol(value, Decl(narrowingMutualSubtypes.ts, 60, 15))
|
||||
>Self : Symbol(Self, Decl(narrowingMutualSubtypes.ts, 56, 42))
|
||||
>T : Symbol(T, Decl(narrowingMutualSubtypes.ts, 60, 12))
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
type Union = {a: number} | {b: number} | {c: number};
|
||||
>Union : Symbol(Union, Decl(narrowingMutualSubtypes.ts, 62, 1))
|
||||
>a : Symbol(a, Decl(narrowingMutualSubtypes.ts, 64, 15))
|
||||
>b : Symbol(b, Decl(narrowingMutualSubtypes.ts, 64, 29))
|
||||
>c : Symbol(c, Decl(narrowingMutualSubtypes.ts, 64, 43))
|
||||
|
||||
function example(x: Union) {
|
||||
>example : Symbol(example, Decl(narrowingMutualSubtypes.ts, 64, 54))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
>Union : Symbol(Union, Decl(narrowingMutualSubtypes.ts, 62, 1))
|
||||
|
||||
if (is(x)) {}
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
|
||||
if (is(x)) {}
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
|
||||
if (is(x)) {}
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
|
||||
if (is(x)) {}
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
|
||||
if (is(x)) {}
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
|
||||
if (is(x)) {}
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
|
||||
if (is(x)) {}
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
|
||||
if (is(x)) {}
|
||||
>is : Symbol(is, Decl(narrowingMutualSubtypes.ts, 58, 55))
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
|
||||
x; // Union
|
||||
>x : Symbol(x, Decl(narrowingMutualSubtypes.ts, 66, 17))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
=== tests/cases/compiler/narrowingMutualSubtypes.ts ===
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const ru1: { [x: string]: unknown };
|
||||
>ru1 : { [x: string]: unknown; }
|
||||
>x : string
|
||||
|
||||
declare const ra1: { [x: string]: any };
|
||||
>ra1 : { [x: string]: any; }
|
||||
>x : string
|
||||
|
||||
const a1a = [ru1, ra1]; // { [x: string]: any }[]
|
||||
>a1a : { [x: string]: any; }[]
|
||||
>[ru1, ra1] : { [x: string]: any; }[]
|
||||
>ru1 : { [x: string]: unknown; }
|
||||
>ra1 : { [x: string]: any; }
|
||||
|
||||
const a1b = [ra1, ru1]; // { [x: string]: any }[]
|
||||
>a1b : { [x: string]: any; }[]
|
||||
>[ra1, ru1] : { [x: string]: any; }[]
|
||||
>ra1 : { [x: string]: any; }
|
||||
>ru1 : { [x: string]: unknown; }
|
||||
|
||||
declare const ra2: { [x: string]: any };
|
||||
>ra2 : { [x: string]: any; }
|
||||
>x : string
|
||||
|
||||
declare const ru2: { [x: string]: unknown };
|
||||
>ru2 : { [x: string]: unknown; }
|
||||
>x : string
|
||||
|
||||
const a2a = [ru2, ra2]; // { [x: string]: any }[]
|
||||
>a2a : { [x: string]: any; }[]
|
||||
>[ru2, ra2] : { [x: string]: any; }[]
|
||||
>ru2 : { [x: string]: unknown; }
|
||||
>ra2 : { [x: string]: any; }
|
||||
|
||||
const a2b = [ra2, ru2]; // { [x: string]: any }[]
|
||||
>a2b : { [x: string]: any; }[]
|
||||
>[ra2, ru2] : { [x: string]: any; }[]
|
||||
>ra2 : { [x: string]: any; }
|
||||
>ru2 : { [x: string]: unknown; }
|
||||
|
||||
// Check that `{}` is strict supertype of any non-empty object
|
||||
|
||||
const c3 = {};
|
||||
>c3 : {}
|
||||
>{} : {}
|
||||
|
||||
declare const r3: { [x: string]: unknown }
|
||||
>r3 : { [x: string]: unknown; }
|
||||
>x : string
|
||||
|
||||
const a3a = [c3, r3]; // {}[]
|
||||
>a3a : {}[]
|
||||
>[c3, r3] : {}[]
|
||||
>c3 : {}
|
||||
>r3 : { [x: string]: unknown; }
|
||||
|
||||
const a3b = [r3, c3]; // {}[]
|
||||
>a3b : {}[]
|
||||
>[r3, c3] : {}[]
|
||||
>r3 : { [x: string]: unknown; }
|
||||
>c3 : {}
|
||||
|
||||
declare const r4: { [x: string]: unknown }
|
||||
>r4 : { [x: string]: unknown; }
|
||||
>x : string
|
||||
|
||||
const c4 = {};
|
||||
>c4 : {}
|
||||
>{} : {}
|
||||
|
||||
const a4a = [c4, r4]; // {}[]
|
||||
>a4a : {}[]
|
||||
>[c4, r4] : {}[]
|
||||
>c4 : {}
|
||||
>r4 : { [x: string]: unknown; }
|
||||
|
||||
const a4b = [r4, c4]; // {}[]
|
||||
>a4b : {}[]
|
||||
>[r4, c4] : {}[]
|
||||
>r4 : { [x: string]: unknown; }
|
||||
>c4 : {}
|
||||
|
||||
// Check that narrowing preserves original type in false branch for non-identical mutual subtypes
|
||||
|
||||
declare function isObject1(value: unknown): value is Record<string, unknown>;
|
||||
>isObject1 : (value: unknown) => value is Record<string, unknown>
|
||||
>value : unknown
|
||||
|
||||
function gg(x: {}) {
|
||||
>gg : (x: {}) => void
|
||||
>x : {}
|
||||
|
||||
if (isObject1(x)) {
|
||||
>isObject1(x) : boolean
|
||||
>isObject1 : (value: unknown) => value is Record<string, unknown>
|
||||
>x : {}
|
||||
|
||||
x; // Record<string, unknown>
|
||||
>x : Record<string, unknown>
|
||||
}
|
||||
else {
|
||||
x; // {}
|
||||
>x : {}
|
||||
}
|
||||
x; // {}
|
||||
>x : {}
|
||||
}
|
||||
|
||||
declare function isObject2(value: unknown): value is {};
|
||||
>isObject2 : (value: unknown) => value is {}
|
||||
>value : unknown
|
||||
|
||||
function gg2(x: Record<string, unknown>) {
|
||||
>gg2 : (x: Record<string, unknown>) => void
|
||||
>x : Record<string, unknown>
|
||||
|
||||
if (isObject2(x)) {
|
||||
>isObject2(x) : boolean
|
||||
>isObject2 : (value: unknown) => value is {}
|
||||
>x : Record<string, unknown>
|
||||
|
||||
x; // {}
|
||||
>x : {}
|
||||
}
|
||||
else {
|
||||
x; // Record<string, unknown>
|
||||
>x : Record<string, unknown>
|
||||
}
|
||||
x; // Record<string, unknown>
|
||||
>x : Record<string, unknown>
|
||||
}
|
||||
|
||||
// Repro from #50916
|
||||
|
||||
type Identity<T> = {[K in keyof T]: T[K]};
|
||||
>Identity : Identity<T>
|
||||
|
||||
type Self<T> = T extends unknown ? Identity<T> : never;
|
||||
>Self : Self<T>
|
||||
|
||||
function is<T>(value: T): value is Self<T> {
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>value : T
|
||||
|
||||
return true;
|
||||
>true : true
|
||||
}
|
||||
|
||||
type Union = {a: number} | {b: number} | {c: number};
|
||||
>Union : { a: number; } | { b: number; } | { c: number; }
|
||||
>a : number
|
||||
>b : number
|
||||
>c : number
|
||||
|
||||
function example(x: Union) {
|
||||
>example : (x: Union) => void
|
||||
>x : Union
|
||||
|
||||
if (is(x)) {}
|
||||
>is(x) : boolean
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>x : Union
|
||||
|
||||
if (is(x)) {}
|
||||
>is(x) : boolean
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>x : Union
|
||||
|
||||
if (is(x)) {}
|
||||
>is(x) : boolean
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>x : Union
|
||||
|
||||
if (is(x)) {}
|
||||
>is(x) : boolean
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>x : Union
|
||||
|
||||
if (is(x)) {}
|
||||
>is(x) : boolean
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>x : Union
|
||||
|
||||
if (is(x)) {}
|
||||
>is(x) : boolean
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>x : Union
|
||||
|
||||
if (is(x)) {}
|
||||
>is(x) : boolean
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>x : Union
|
||||
|
||||
if (is(x)) {}
|
||||
>is(x) : boolean
|
||||
>is : <T>(value: T) => value is Self<T>
|
||||
>x : Union
|
||||
|
||||
x; // Union
|
||||
>x : Union
|
||||
}
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
tests/cases/compiler/strictSubtypeAndNarrowing.ts(123,27): error TS2322: Type '{ x: number; y: number; }' is not assignable to type '{ x?: number | undefined; }'.
|
||||
Object literal may only specify known properties, and 'y' does not exist in type '{ x?: number | undefined; }'.
|
||||
tests/cases/compiler/strictSubtypeAndNarrowing.ts(124,27): error TS2322: Type '{ x: number; y: number; }' is not assignable to type '{ x?: number | undefined; }'.
|
||||
Object literal may only specify known properties, and 'y' does not exist in type '{ x?: number | undefined; }'.
|
||||
tests/cases/compiler/strictSubtypeAndNarrowing.ts(129,26): error TS2322: Type '{ x: number; y: number; }' is not assignable to type '{ x?: number | undefined; }'.
|
||||
Object literal may only specify known properties, and 'y' does not exist in type '{ x?: number | undefined; }'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/strictSubtypeAndNarrowing.ts (3 errors) ====
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const x11: { x: unknown };
|
||||
declare const x12: { x: any };
|
||||
|
||||
const a11 = [x11, x12];
|
||||
const a12 = [x12, x11];
|
||||
|
||||
declare const x21: { x: any };
|
||||
declare const x22: { x: unknown };
|
||||
|
||||
const a21 = [x22, x21];
|
||||
const a22 = [x21, x22];
|
||||
|
||||
// Strict subtype doesn't infer index signatures in non-fresh object types
|
||||
|
||||
const x31 = { a: 1 };
|
||||
declare const x32: { [x: string]: unknown, a: number }
|
||||
|
||||
const a31 = [x31, x32];
|
||||
const a32 = [x32, x31];
|
||||
|
||||
declare const x41: { [x: string]: unknown, a: number }
|
||||
const x42 = { a: 1 };
|
||||
|
||||
const a41 = [x42, x41];
|
||||
const a42 = [x41, x42];
|
||||
|
||||
// (...args: A) => R, where A is any, any[], never, or never[] and R is any or unknown, is supertype of all function types.
|
||||
|
||||
declare function isFunction<T>(x: unknown): x is T;
|
||||
|
||||
type A = (...args: any) => unknown;
|
||||
type B = (...args: any[]) => unknown;
|
||||
type C = (...args: never) => unknown;
|
||||
type D = (...args: never[]) => unknown;
|
||||
|
||||
type FnTypes = A | B | C | D;
|
||||
|
||||
function fx1(f: (() => void) | undefined) {
|
||||
if (isFunction<A>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx2(f: (() => void) | undefined) {
|
||||
if (isFunction<B>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx3(f: (() => void) | undefined) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx4(f: (() => void) | undefined) {
|
||||
if (isFunction<D>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function checkA(f: FnTypes) {
|
||||
if (isFunction<A>(f)) {
|
||||
f; // A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkB(f: FnTypes) {
|
||||
if (isFunction<B>(f)) {
|
||||
f; // A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkC(f: FnTypes) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkD(f: FnTypes) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
// Type of x = y is y with freshness preserved
|
||||
|
||||
function fx10(obj1: { x?: number }, obj2: { x?: number, y?: number }) {
|
||||
obj1 = obj2 = { x: 1, y: 2 };
|
||||
~~~~
|
||||
!!! error TS2322: Type '{ x: number; y: number; }' is not assignable to type '{ x?: number | undefined; }'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'y' does not exist in type '{ x?: number | undefined; }'.
|
||||
obj2 = obj1 = { x: 1, y: 2 };
|
||||
~~~~
|
||||
!!! error TS2322: Type '{ x: number; y: number; }' is not assignable to type '{ x?: number | undefined; }'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'y' does not exist in type '{ x?: number | undefined; }'.
|
||||
}
|
||||
|
||||
function fx11(): { x?: number } {
|
||||
let obj: { x?: number, y?: number };
|
||||
return obj = { x: 1, y: 2 };
|
||||
~~~~
|
||||
!!! error TS2322: Type '{ x: number; y: number; }' is not assignable to type '{ x?: number | undefined; }'.
|
||||
!!! error TS2322: Object literal may only specify known properties, and 'y' does not exist in type '{ x?: number | undefined; }'.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
//// [strictSubtypeAndNarrowing.ts]
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const x11: { x: unknown };
|
||||
declare const x12: { x: any };
|
||||
|
||||
const a11 = [x11, x12];
|
||||
const a12 = [x12, x11];
|
||||
|
||||
declare const x21: { x: any };
|
||||
declare const x22: { x: unknown };
|
||||
|
||||
const a21 = [x22, x21];
|
||||
const a22 = [x21, x22];
|
||||
|
||||
// Strict subtype doesn't infer index signatures in non-fresh object types
|
||||
|
||||
const x31 = { a: 1 };
|
||||
declare const x32: { [x: string]: unknown, a: number }
|
||||
|
||||
const a31 = [x31, x32];
|
||||
const a32 = [x32, x31];
|
||||
|
||||
declare const x41: { [x: string]: unknown, a: number }
|
||||
const x42 = { a: 1 };
|
||||
|
||||
const a41 = [x42, x41];
|
||||
const a42 = [x41, x42];
|
||||
|
||||
// (...args: A) => R, where A is any, any[], never, or never[] and R is any or unknown, is supertype of all function types.
|
||||
|
||||
declare function isFunction<T>(x: unknown): x is T;
|
||||
|
||||
type A = (...args: any) => unknown;
|
||||
type B = (...args: any[]) => unknown;
|
||||
type C = (...args: never) => unknown;
|
||||
type D = (...args: never[]) => unknown;
|
||||
|
||||
type FnTypes = A | B | C | D;
|
||||
|
||||
function fx1(f: (() => void) | undefined) {
|
||||
if (isFunction<A>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx2(f: (() => void) | undefined) {
|
||||
if (isFunction<B>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx3(f: (() => void) | undefined) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx4(f: (() => void) | undefined) {
|
||||
if (isFunction<D>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function checkA(f: FnTypes) {
|
||||
if (isFunction<A>(f)) {
|
||||
f; // A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkB(f: FnTypes) {
|
||||
if (isFunction<B>(f)) {
|
||||
f; // A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkC(f: FnTypes) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkD(f: FnTypes) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
// Type of x = y is y with freshness preserved
|
||||
|
||||
function fx10(obj1: { x?: number }, obj2: { x?: number, y?: number }) {
|
||||
obj1 = obj2 = { x: 1, y: 2 };
|
||||
obj2 = obj1 = { x: 1, y: 2 };
|
||||
}
|
||||
|
||||
function fx11(): { x?: number } {
|
||||
let obj: { x?: number, y?: number };
|
||||
return obj = { x: 1, y: 2 };
|
||||
}
|
||||
|
||||
|
||||
//// [strictSubtypeAndNarrowing.js]
|
||||
"use strict";
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
var a11 = [x11, x12];
|
||||
var a12 = [x12, x11];
|
||||
var a21 = [x22, x21];
|
||||
var a22 = [x21, x22];
|
||||
// Strict subtype doesn't infer index signatures in non-fresh object types
|
||||
var x31 = { a: 1 };
|
||||
var a31 = [x31, x32];
|
||||
var a32 = [x32, x31];
|
||||
var x42 = { a: 1 };
|
||||
var a41 = [x42, x41];
|
||||
var a42 = [x41, x42];
|
||||
function fx1(f) {
|
||||
if (isFunction(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
function fx2(f) {
|
||||
if (isFunction(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
function fx3(f) {
|
||||
if (isFunction(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
function fx4(f) {
|
||||
if (isFunction(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
function checkA(f) {
|
||||
if (isFunction(f)) {
|
||||
f; // A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
function checkB(f) {
|
||||
if (isFunction(f)) {
|
||||
f; // A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
function checkC(f) {
|
||||
if (isFunction(f)) {
|
||||
f; // FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
function checkD(f) {
|
||||
if (isFunction(f)) {
|
||||
f; // FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
// Type of x = y is y with freshness preserved
|
||||
function fx10(obj1, obj2) {
|
||||
obj1 = obj2 = { x: 1, y: 2 };
|
||||
obj2 = obj1 = { x: 1, y: 2 };
|
||||
}
|
||||
function fx11() {
|
||||
var obj;
|
||||
return obj = { x: 1, y: 2 };
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
=== tests/cases/compiler/strictSubtypeAndNarrowing.ts ===
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const x11: { x: unknown };
|
||||
>x11 : Symbol(x11, Decl(strictSubtypeAndNarrowing.ts, 2, 13))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 2, 20))
|
||||
|
||||
declare const x12: { x: any };
|
||||
>x12 : Symbol(x12, Decl(strictSubtypeAndNarrowing.ts, 3, 13))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 3, 20))
|
||||
|
||||
const a11 = [x11, x12];
|
||||
>a11 : Symbol(a11, Decl(strictSubtypeAndNarrowing.ts, 5, 5))
|
||||
>x11 : Symbol(x11, Decl(strictSubtypeAndNarrowing.ts, 2, 13))
|
||||
>x12 : Symbol(x12, Decl(strictSubtypeAndNarrowing.ts, 3, 13))
|
||||
|
||||
const a12 = [x12, x11];
|
||||
>a12 : Symbol(a12, Decl(strictSubtypeAndNarrowing.ts, 6, 5))
|
||||
>x12 : Symbol(x12, Decl(strictSubtypeAndNarrowing.ts, 3, 13))
|
||||
>x11 : Symbol(x11, Decl(strictSubtypeAndNarrowing.ts, 2, 13))
|
||||
|
||||
declare const x21: { x: any };
|
||||
>x21 : Symbol(x21, Decl(strictSubtypeAndNarrowing.ts, 8, 13))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 8, 20))
|
||||
|
||||
declare const x22: { x: unknown };
|
||||
>x22 : Symbol(x22, Decl(strictSubtypeAndNarrowing.ts, 9, 13))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 9, 20))
|
||||
|
||||
const a21 = [x22, x21];
|
||||
>a21 : Symbol(a21, Decl(strictSubtypeAndNarrowing.ts, 11, 5))
|
||||
>x22 : Symbol(x22, Decl(strictSubtypeAndNarrowing.ts, 9, 13))
|
||||
>x21 : Symbol(x21, Decl(strictSubtypeAndNarrowing.ts, 8, 13))
|
||||
|
||||
const a22 = [x21, x22];
|
||||
>a22 : Symbol(a22, Decl(strictSubtypeAndNarrowing.ts, 12, 5))
|
||||
>x21 : Symbol(x21, Decl(strictSubtypeAndNarrowing.ts, 8, 13))
|
||||
>x22 : Symbol(x22, Decl(strictSubtypeAndNarrowing.ts, 9, 13))
|
||||
|
||||
// Strict subtype doesn't infer index signatures in non-fresh object types
|
||||
|
||||
const x31 = { a: 1 };
|
||||
>x31 : Symbol(x31, Decl(strictSubtypeAndNarrowing.ts, 16, 5))
|
||||
>a : Symbol(a, Decl(strictSubtypeAndNarrowing.ts, 16, 13))
|
||||
|
||||
declare const x32: { [x: string]: unknown, a: number }
|
||||
>x32 : Symbol(x32, Decl(strictSubtypeAndNarrowing.ts, 17, 13))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 17, 22))
|
||||
>a : Symbol(a, Decl(strictSubtypeAndNarrowing.ts, 17, 42))
|
||||
|
||||
const a31 = [x31, x32];
|
||||
>a31 : Symbol(a31, Decl(strictSubtypeAndNarrowing.ts, 19, 5))
|
||||
>x31 : Symbol(x31, Decl(strictSubtypeAndNarrowing.ts, 16, 5))
|
||||
>x32 : Symbol(x32, Decl(strictSubtypeAndNarrowing.ts, 17, 13))
|
||||
|
||||
const a32 = [x32, x31];
|
||||
>a32 : Symbol(a32, Decl(strictSubtypeAndNarrowing.ts, 20, 5))
|
||||
>x32 : Symbol(x32, Decl(strictSubtypeAndNarrowing.ts, 17, 13))
|
||||
>x31 : Symbol(x31, Decl(strictSubtypeAndNarrowing.ts, 16, 5))
|
||||
|
||||
declare const x41: { [x: string]: unknown, a: number }
|
||||
>x41 : Symbol(x41, Decl(strictSubtypeAndNarrowing.ts, 22, 13))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 22, 22))
|
||||
>a : Symbol(a, Decl(strictSubtypeAndNarrowing.ts, 22, 42))
|
||||
|
||||
const x42 = { a: 1 };
|
||||
>x42 : Symbol(x42, Decl(strictSubtypeAndNarrowing.ts, 23, 5))
|
||||
>a : Symbol(a, Decl(strictSubtypeAndNarrowing.ts, 23, 13))
|
||||
|
||||
const a41 = [x42, x41];
|
||||
>a41 : Symbol(a41, Decl(strictSubtypeAndNarrowing.ts, 25, 5))
|
||||
>x42 : Symbol(x42, Decl(strictSubtypeAndNarrowing.ts, 23, 5))
|
||||
>x41 : Symbol(x41, Decl(strictSubtypeAndNarrowing.ts, 22, 13))
|
||||
|
||||
const a42 = [x41, x42];
|
||||
>a42 : Symbol(a42, Decl(strictSubtypeAndNarrowing.ts, 26, 5))
|
||||
>x41 : Symbol(x41, Decl(strictSubtypeAndNarrowing.ts, 22, 13))
|
||||
>x42 : Symbol(x42, Decl(strictSubtypeAndNarrowing.ts, 23, 5))
|
||||
|
||||
// (...args: A) => R, where A is any, any[], never, or never[] and R is any or unknown, is supertype of all function types.
|
||||
|
||||
declare function isFunction<T>(x: unknown): x is T;
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>T : Symbol(T, Decl(strictSubtypeAndNarrowing.ts, 30, 28))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 30, 31))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 30, 31))
|
||||
>T : Symbol(T, Decl(strictSubtypeAndNarrowing.ts, 30, 28))
|
||||
|
||||
type A = (...args: any) => unknown;
|
||||
>A : Symbol(A, Decl(strictSubtypeAndNarrowing.ts, 30, 51))
|
||||
>args : Symbol(args, Decl(strictSubtypeAndNarrowing.ts, 32, 10))
|
||||
|
||||
type B = (...args: any[]) => unknown;
|
||||
>B : Symbol(B, Decl(strictSubtypeAndNarrowing.ts, 32, 35))
|
||||
>args : Symbol(args, Decl(strictSubtypeAndNarrowing.ts, 33, 10))
|
||||
|
||||
type C = (...args: never) => unknown;
|
||||
>C : Symbol(C, Decl(strictSubtypeAndNarrowing.ts, 33, 37))
|
||||
>args : Symbol(args, Decl(strictSubtypeAndNarrowing.ts, 34, 10))
|
||||
|
||||
type D = (...args: never[]) => unknown;
|
||||
>D : Symbol(D, Decl(strictSubtypeAndNarrowing.ts, 34, 37))
|
||||
>args : Symbol(args, Decl(strictSubtypeAndNarrowing.ts, 35, 10))
|
||||
|
||||
type FnTypes = A | B | C | D;
|
||||
>FnTypes : Symbol(FnTypes, Decl(strictSubtypeAndNarrowing.ts, 35, 39))
|
||||
>A : Symbol(A, Decl(strictSubtypeAndNarrowing.ts, 30, 51))
|
||||
>B : Symbol(B, Decl(strictSubtypeAndNarrowing.ts, 32, 35))
|
||||
>C : Symbol(C, Decl(strictSubtypeAndNarrowing.ts, 33, 37))
|
||||
>D : Symbol(D, Decl(strictSubtypeAndNarrowing.ts, 34, 37))
|
||||
|
||||
function fx1(f: (() => void) | undefined) {
|
||||
>fx1 : Symbol(fx1, Decl(strictSubtypeAndNarrowing.ts, 37, 29))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 39, 13))
|
||||
|
||||
if (isFunction<A>(f)) {
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>A : Symbol(A, Decl(strictSubtypeAndNarrowing.ts, 30, 51))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 39, 13))
|
||||
|
||||
f; // () => void
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 39, 13))
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 39, 13))
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 39, 13))
|
||||
}
|
||||
|
||||
function fx2(f: (() => void) | undefined) {
|
||||
>fx2 : Symbol(fx2, Decl(strictSubtypeAndNarrowing.ts, 47, 1))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 49, 13))
|
||||
|
||||
if (isFunction<B>(f)) {
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>B : Symbol(B, Decl(strictSubtypeAndNarrowing.ts, 32, 35))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 49, 13))
|
||||
|
||||
f; // () => void
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 49, 13))
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 49, 13))
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 49, 13))
|
||||
}
|
||||
|
||||
function fx3(f: (() => void) | undefined) {
|
||||
>fx3 : Symbol(fx3, Decl(strictSubtypeAndNarrowing.ts, 57, 1))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 59, 13))
|
||||
|
||||
if (isFunction<C>(f)) {
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>C : Symbol(C, Decl(strictSubtypeAndNarrowing.ts, 33, 37))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 59, 13))
|
||||
|
||||
f; // () => void
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 59, 13))
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 59, 13))
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 59, 13))
|
||||
}
|
||||
|
||||
function fx4(f: (() => void) | undefined) {
|
||||
>fx4 : Symbol(fx4, Decl(strictSubtypeAndNarrowing.ts, 67, 1))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 69, 13))
|
||||
|
||||
if (isFunction<D>(f)) {
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>D : Symbol(D, Decl(strictSubtypeAndNarrowing.ts, 34, 37))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 69, 13))
|
||||
|
||||
f; // () => void
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 69, 13))
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 69, 13))
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 69, 13))
|
||||
}
|
||||
|
||||
function checkA(f: FnTypes) {
|
||||
>checkA : Symbol(checkA, Decl(strictSubtypeAndNarrowing.ts, 77, 1))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 79, 16))
|
||||
>FnTypes : Symbol(FnTypes, Decl(strictSubtypeAndNarrowing.ts, 35, 39))
|
||||
|
||||
if (isFunction<A>(f)) {
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>A : Symbol(A, Decl(strictSubtypeAndNarrowing.ts, 30, 51))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 79, 16))
|
||||
|
||||
f; // A | B
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 79, 16))
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 79, 16))
|
||||
}
|
||||
f; // FnTypes
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 79, 16))
|
||||
}
|
||||
|
||||
function checkB(f: FnTypes) {
|
||||
>checkB : Symbol(checkB, Decl(strictSubtypeAndNarrowing.ts, 87, 1))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 89, 16))
|
||||
>FnTypes : Symbol(FnTypes, Decl(strictSubtypeAndNarrowing.ts, 35, 39))
|
||||
|
||||
if (isFunction<B>(f)) {
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>B : Symbol(B, Decl(strictSubtypeAndNarrowing.ts, 32, 35))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 89, 16))
|
||||
|
||||
f; // A | B
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 89, 16))
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 89, 16))
|
||||
}
|
||||
f; // FnTypes
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 89, 16))
|
||||
}
|
||||
|
||||
function checkC(f: FnTypes) {
|
||||
>checkC : Symbol(checkC, Decl(strictSubtypeAndNarrowing.ts, 97, 1))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 99, 16))
|
||||
>FnTypes : Symbol(FnTypes, Decl(strictSubtypeAndNarrowing.ts, 35, 39))
|
||||
|
||||
if (isFunction<C>(f)) {
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>C : Symbol(C, Decl(strictSubtypeAndNarrowing.ts, 33, 37))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 99, 16))
|
||||
|
||||
f; // FnTypes
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 99, 16))
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 99, 16))
|
||||
}
|
||||
f; // FnTypes
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 99, 16))
|
||||
}
|
||||
|
||||
function checkD(f: FnTypes) {
|
||||
>checkD : Symbol(checkD, Decl(strictSubtypeAndNarrowing.ts, 107, 1))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 109, 16))
|
||||
>FnTypes : Symbol(FnTypes, Decl(strictSubtypeAndNarrowing.ts, 35, 39))
|
||||
|
||||
if (isFunction<C>(f)) {
|
||||
>isFunction : Symbol(isFunction, Decl(strictSubtypeAndNarrowing.ts, 26, 23))
|
||||
>C : Symbol(C, Decl(strictSubtypeAndNarrowing.ts, 33, 37))
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 109, 16))
|
||||
|
||||
f; // FnTypes
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 109, 16))
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 109, 16))
|
||||
}
|
||||
f; // FnTypes
|
||||
>f : Symbol(f, Decl(strictSubtypeAndNarrowing.ts, 109, 16))
|
||||
}
|
||||
|
||||
// Type of x = y is y with freshness preserved
|
||||
|
||||
function fx10(obj1: { x?: number }, obj2: { x?: number, y?: number }) {
|
||||
>fx10 : Symbol(fx10, Decl(strictSubtypeAndNarrowing.ts, 117, 1))
|
||||
>obj1 : Symbol(obj1, Decl(strictSubtypeAndNarrowing.ts, 121, 14))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 121, 21))
|
||||
>obj2 : Symbol(obj2, Decl(strictSubtypeAndNarrowing.ts, 121, 35))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 121, 43))
|
||||
>y : Symbol(y, Decl(strictSubtypeAndNarrowing.ts, 121, 55))
|
||||
|
||||
obj1 = obj2 = { x: 1, y: 2 };
|
||||
>obj1 : Symbol(obj1, Decl(strictSubtypeAndNarrowing.ts, 121, 14))
|
||||
>obj2 : Symbol(obj2, Decl(strictSubtypeAndNarrowing.ts, 121, 35))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 122, 19))
|
||||
>y : Symbol(y, Decl(strictSubtypeAndNarrowing.ts, 122, 25))
|
||||
|
||||
obj2 = obj1 = { x: 1, y: 2 };
|
||||
>obj2 : Symbol(obj2, Decl(strictSubtypeAndNarrowing.ts, 121, 35))
|
||||
>obj1 : Symbol(obj1, Decl(strictSubtypeAndNarrowing.ts, 121, 14))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 123, 19))
|
||||
>y : Symbol(y, Decl(strictSubtypeAndNarrowing.ts, 123, 25))
|
||||
}
|
||||
|
||||
function fx11(): { x?: number } {
|
||||
>fx11 : Symbol(fx11, Decl(strictSubtypeAndNarrowing.ts, 124, 1))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 126, 18))
|
||||
|
||||
let obj: { x?: number, y?: number };
|
||||
>obj : Symbol(obj, Decl(strictSubtypeAndNarrowing.ts, 127, 7))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 127, 14))
|
||||
>y : Symbol(y, Decl(strictSubtypeAndNarrowing.ts, 127, 26))
|
||||
|
||||
return obj = { x: 1, y: 2 };
|
||||
>obj : Symbol(obj, Decl(strictSubtypeAndNarrowing.ts, 127, 7))
|
||||
>x : Symbol(x, Decl(strictSubtypeAndNarrowing.ts, 128, 18))
|
||||
>y : Symbol(y, Decl(strictSubtypeAndNarrowing.ts, 128, 24))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
=== tests/cases/compiler/strictSubtypeAndNarrowing.ts ===
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const x11: { x: unknown };
|
||||
>x11 : { x: unknown; }
|
||||
>x : unknown
|
||||
|
||||
declare const x12: { x: any };
|
||||
>x12 : { x: any; }
|
||||
>x : any
|
||||
|
||||
const a11 = [x11, x12];
|
||||
>a11 : { x: any; }[]
|
||||
>[x11, x12] : { x: any; }[]
|
||||
>x11 : { x: unknown; }
|
||||
>x12 : { x: any; }
|
||||
|
||||
const a12 = [x12, x11];
|
||||
>a12 : { x: any; }[]
|
||||
>[x12, x11] : { x: any; }[]
|
||||
>x12 : { x: any; }
|
||||
>x11 : { x: unknown; }
|
||||
|
||||
declare const x21: { x: any };
|
||||
>x21 : { x: any; }
|
||||
>x : any
|
||||
|
||||
declare const x22: { x: unknown };
|
||||
>x22 : { x: unknown; }
|
||||
>x : unknown
|
||||
|
||||
const a21 = [x22, x21];
|
||||
>a21 : { x: any; }[]
|
||||
>[x22, x21] : { x: any; }[]
|
||||
>x22 : { x: unknown; }
|
||||
>x21 : { x: any; }
|
||||
|
||||
const a22 = [x21, x22];
|
||||
>a22 : { x: any; }[]
|
||||
>[x21, x22] : { x: any; }[]
|
||||
>x21 : { x: any; }
|
||||
>x22 : { x: unknown; }
|
||||
|
||||
// Strict subtype doesn't infer index signatures in non-fresh object types
|
||||
|
||||
const x31 = { a: 1 };
|
||||
>x31 : { a: number; }
|
||||
>{ a: 1 } : { a: number; }
|
||||
>a : number
|
||||
>1 : 1
|
||||
|
||||
declare const x32: { [x: string]: unknown, a: number }
|
||||
>x32 : { [x: string]: unknown; a: number; }
|
||||
>x : string
|
||||
>a : number
|
||||
|
||||
const a31 = [x31, x32];
|
||||
>a31 : { a: number; }[]
|
||||
>[x31, x32] : { a: number; }[]
|
||||
>x31 : { a: number; }
|
||||
>x32 : { [x: string]: unknown; a: number; }
|
||||
|
||||
const a32 = [x32, x31];
|
||||
>a32 : { a: number; }[]
|
||||
>[x32, x31] : { a: number; }[]
|
||||
>x32 : { [x: string]: unknown; a: number; }
|
||||
>x31 : { a: number; }
|
||||
|
||||
declare const x41: { [x: string]: unknown, a: number }
|
||||
>x41 : { [x: string]: unknown; a: number; }
|
||||
>x : string
|
||||
>a : number
|
||||
|
||||
const x42 = { a: 1 };
|
||||
>x42 : { a: number; }
|
||||
>{ a: 1 } : { a: number; }
|
||||
>a : number
|
||||
>1 : 1
|
||||
|
||||
const a41 = [x42, x41];
|
||||
>a41 : { a: number; }[]
|
||||
>[x42, x41] : { a: number; }[]
|
||||
>x42 : { a: number; }
|
||||
>x41 : { [x: string]: unknown; a: number; }
|
||||
|
||||
const a42 = [x41, x42];
|
||||
>a42 : { a: number; }[]
|
||||
>[x41, x42] : { a: number; }[]
|
||||
>x41 : { [x: string]: unknown; a: number; }
|
||||
>x42 : { a: number; }
|
||||
|
||||
// (...args: A) => R, where A is any, any[], never, or never[] and R is any or unknown, is supertype of all function types.
|
||||
|
||||
declare function isFunction<T>(x: unknown): x is T;
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>x : unknown
|
||||
|
||||
type A = (...args: any) => unknown;
|
||||
>A : (...args: any) => unknown
|
||||
>args : any
|
||||
|
||||
type B = (...args: any[]) => unknown;
|
||||
>B : (...args: any[]) => unknown
|
||||
>args : any[]
|
||||
|
||||
type C = (...args: never) => unknown;
|
||||
>C : (...args: never) => unknown
|
||||
>args : never
|
||||
|
||||
type D = (...args: never[]) => unknown;
|
||||
>D : (...args: never[]) => unknown
|
||||
>args : never[]
|
||||
|
||||
type FnTypes = A | B | C | D;
|
||||
>FnTypes : A | B | C | D
|
||||
|
||||
function fx1(f: (() => void) | undefined) {
|
||||
>fx1 : (f: (() => void) | undefined) => void
|
||||
>f : (() => void) | undefined
|
||||
|
||||
if (isFunction<A>(f)) {
|
||||
>isFunction<A>(f) : boolean
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>f : (() => void) | undefined
|
||||
|
||||
f; // () => void
|
||||
>f : () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
>f : undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
>f : (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx2(f: (() => void) | undefined) {
|
||||
>fx2 : (f: (() => void) | undefined) => void
|
||||
>f : (() => void) | undefined
|
||||
|
||||
if (isFunction<B>(f)) {
|
||||
>isFunction<B>(f) : boolean
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>f : (() => void) | undefined
|
||||
|
||||
f; // () => void
|
||||
>f : () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
>f : undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
>f : (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx3(f: (() => void) | undefined) {
|
||||
>fx3 : (f: (() => void) | undefined) => void
|
||||
>f : (() => void) | undefined
|
||||
|
||||
if (isFunction<C>(f)) {
|
||||
>isFunction<C>(f) : boolean
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>f : (() => void) | undefined
|
||||
|
||||
f; // () => void
|
||||
>f : () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
>f : undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
>f : (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx4(f: (() => void) | undefined) {
|
||||
>fx4 : (f: (() => void) | undefined) => void
|
||||
>f : (() => void) | undefined
|
||||
|
||||
if (isFunction<D>(f)) {
|
||||
>isFunction<D>(f) : boolean
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>f : (() => void) | undefined
|
||||
|
||||
f; // () => void
|
||||
>f : () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
>f : undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
>f : (() => void) | undefined
|
||||
}
|
||||
|
||||
function checkA(f: FnTypes) {
|
||||
>checkA : (f: FnTypes) => void
|
||||
>f : FnTypes
|
||||
|
||||
if (isFunction<A>(f)) {
|
||||
>isFunction<A>(f) : boolean
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>f : FnTypes
|
||||
|
||||
f; // A | B
|
||||
>f : A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
>f : C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
>f : FnTypes
|
||||
}
|
||||
|
||||
function checkB(f: FnTypes) {
|
||||
>checkB : (f: FnTypes) => void
|
||||
>f : FnTypes
|
||||
|
||||
if (isFunction<B>(f)) {
|
||||
>isFunction<B>(f) : boolean
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>f : FnTypes
|
||||
|
||||
f; // A | B
|
||||
>f : A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
>f : C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
>f : FnTypes
|
||||
}
|
||||
|
||||
function checkC(f: FnTypes) {
|
||||
>checkC : (f: FnTypes) => void
|
||||
>f : FnTypes
|
||||
|
||||
if (isFunction<C>(f)) {
|
||||
>isFunction<C>(f) : boolean
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>f : FnTypes
|
||||
|
||||
f; // FnTypes
|
||||
>f : FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
>f : never
|
||||
}
|
||||
f; // FnTypes
|
||||
>f : FnTypes
|
||||
}
|
||||
|
||||
function checkD(f: FnTypes) {
|
||||
>checkD : (f: FnTypes) => void
|
||||
>f : FnTypes
|
||||
|
||||
if (isFunction<C>(f)) {
|
||||
>isFunction<C>(f) : boolean
|
||||
>isFunction : <T>(x: unknown) => x is T
|
||||
>f : FnTypes
|
||||
|
||||
f; // FnTypes
|
||||
>f : FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
>f : never
|
||||
}
|
||||
f; // FnTypes
|
||||
>f : FnTypes
|
||||
}
|
||||
|
||||
// Type of x = y is y with freshness preserved
|
||||
|
||||
function fx10(obj1: { x?: number }, obj2: { x?: number, y?: number }) {
|
||||
>fx10 : (obj1: { x?: number;}, obj2: { x?: number; y?: number;}) => void
|
||||
>obj1 : { x?: number | undefined; }
|
||||
>x : number | undefined
|
||||
>obj2 : { x?: number | undefined; y?: number | undefined; }
|
||||
>x : number | undefined
|
||||
>y : number | undefined
|
||||
|
||||
obj1 = obj2 = { x: 1, y: 2 };
|
||||
>obj1 = obj2 = { x: 1, y: 2 } : { x: number; y: number; }
|
||||
>obj1 : { x?: number | undefined; }
|
||||
>obj2 = { x: 1, y: 2 } : { x: number; y: number; }
|
||||
>obj2 : { x?: number | undefined; y?: number | undefined; }
|
||||
>{ x: 1, y: 2 } : { x: number; y: number; }
|
||||
>x : number
|
||||
>1 : 1
|
||||
>y : number
|
||||
>2 : 2
|
||||
|
||||
obj2 = obj1 = { x: 1, y: 2 };
|
||||
>obj2 = obj1 = { x: 1, y: 2 } : { x: number; y: number; }
|
||||
>obj2 : { x?: number | undefined; y?: number | undefined; }
|
||||
>obj1 = { x: 1, y: 2 } : { x: number; y: number; }
|
||||
>obj1 : { x?: number | undefined; }
|
||||
>{ x: 1, y: 2 } : { x: number; y: number; }
|
||||
>x : number
|
||||
>1 : 1
|
||||
>y : number
|
||||
>2 : 2
|
||||
}
|
||||
|
||||
function fx11(): { x?: number } {
|
||||
>fx11 : () => { x?: number;}
|
||||
>x : number | undefined
|
||||
|
||||
let obj: { x?: number, y?: number };
|
||||
>obj : { x?: number | undefined; y?: number | undefined; }
|
||||
>x : number | undefined
|
||||
>y : number | undefined
|
||||
|
||||
return obj = { x: 1, y: 2 };
|
||||
>obj = { x: 1, y: 2 } : { x: number; y: number; }
|
||||
>obj : { x?: number | undefined; y?: number | undefined; }
|
||||
>{ x: 1, y: 2 } : { x: number; y: number; }
|
||||
>x : number
|
||||
>1 : 1
|
||||
>y : number
|
||||
>2 : 2
|
||||
}
|
||||
|
||||
@@ -51,9 +51,9 @@ function getResults1(value: Results | { data: Results }): Results {
|
||||
return isResponseInData(value) ? value.data : value;
|
||||
>isResponseInData : Symbol(isResponseInData, Decl(typePredicateStructuralMatch.ts, 9, 24))
|
||||
>value : Symbol(value, Decl(typePredicateStructuralMatch.ts, 15, 21))
|
||||
>value.data : Symbol(data, Decl(typePredicateStructuralMatch.ts, 11, 63))
|
||||
>value.data : Symbol(data, Decl(typePredicateStructuralMatch.ts, 15, 39))
|
||||
>value : Symbol(value, Decl(typePredicateStructuralMatch.ts, 15, 21))
|
||||
>data : Symbol(data, Decl(typePredicateStructuralMatch.ts, 11, 63))
|
||||
>data : Symbol(data, Decl(typePredicateStructuralMatch.ts, 15, 39))
|
||||
>value : Symbol(value, Decl(typePredicateStructuralMatch.ts, 15, 21))
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export function flatten<T extends number|TypedArray>(arr: T) {
|
||||
|
||||
arr[1];
|
||||
>arr[1] : number
|
||||
>arr : Int32Array | Uint8Array
|
||||
>arr : TypedArray
|
||||
>1 : 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// @strict: true
|
||||
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const ru1: { [x: string]: unknown };
|
||||
declare const ra1: { [x: string]: any };
|
||||
|
||||
const a1a = [ru1, ra1]; // { [x: string]: any }[]
|
||||
const a1b = [ra1, ru1]; // { [x: string]: any }[]
|
||||
|
||||
declare const ra2: { [x: string]: any };
|
||||
declare const ru2: { [x: string]: unknown };
|
||||
|
||||
const a2a = [ru2, ra2]; // { [x: string]: any }[]
|
||||
const a2b = [ra2, ru2]; // { [x: string]: any }[]
|
||||
|
||||
// Check that `{}` is strict supertype of any non-empty object
|
||||
|
||||
const c3 = {};
|
||||
declare const r3: { [x: string]: unknown }
|
||||
|
||||
const a3a = [c3, r3]; // {}[]
|
||||
const a3b = [r3, c3]; // {}[]
|
||||
|
||||
declare const r4: { [x: string]: unknown }
|
||||
const c4 = {};
|
||||
|
||||
const a4a = [c4, r4]; // {}[]
|
||||
const a4b = [r4, c4]; // {}[]
|
||||
|
||||
// Check that narrowing preserves original type in false branch for non-identical mutual subtypes
|
||||
|
||||
declare function isObject1(value: unknown): value is Record<string, unknown>;
|
||||
|
||||
function gg(x: {}) {
|
||||
if (isObject1(x)) {
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
else {
|
||||
x; // {}
|
||||
}
|
||||
x; // {}
|
||||
}
|
||||
|
||||
declare function isObject2(value: unknown): value is {};
|
||||
|
||||
function gg2(x: Record<string, unknown>) {
|
||||
if (isObject2(x)) {
|
||||
x; // {}
|
||||
}
|
||||
else {
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
x; // Record<string, unknown>
|
||||
}
|
||||
|
||||
// Repro from #50916
|
||||
|
||||
type Identity<T> = {[K in keyof T]: T[K]};
|
||||
|
||||
type Self<T> = T extends unknown ? Identity<T> : never;
|
||||
|
||||
function is<T>(value: T): value is Self<T> {
|
||||
return true;
|
||||
}
|
||||
|
||||
type Union = {a: number} | {b: number} | {c: number};
|
||||
|
||||
function example(x: Union) {
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
if (is(x)) {}
|
||||
x; // Union
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// @strict: true
|
||||
|
||||
// Check that `any` is a strict supertype of `unknown`
|
||||
|
||||
declare const x11: { x: unknown };
|
||||
declare const x12: { x: any };
|
||||
|
||||
const a11 = [x11, x12];
|
||||
const a12 = [x12, x11];
|
||||
|
||||
declare const x21: { x: any };
|
||||
declare const x22: { x: unknown };
|
||||
|
||||
const a21 = [x22, x21];
|
||||
const a22 = [x21, x22];
|
||||
|
||||
// Strict subtype doesn't infer index signatures in non-fresh object types
|
||||
|
||||
const x31 = { a: 1 };
|
||||
declare const x32: { [x: string]: unknown, a: number }
|
||||
|
||||
const a31 = [x31, x32];
|
||||
const a32 = [x32, x31];
|
||||
|
||||
declare const x41: { [x: string]: unknown, a: number }
|
||||
const x42 = { a: 1 };
|
||||
|
||||
const a41 = [x42, x41];
|
||||
const a42 = [x41, x42];
|
||||
|
||||
// (...args: A) => R, where A is any, any[], never, or never[] and R is any or unknown, is supertype of all function types.
|
||||
|
||||
declare function isFunction<T>(x: unknown): x is T;
|
||||
|
||||
type A = (...args: any) => unknown;
|
||||
type B = (...args: any[]) => unknown;
|
||||
type C = (...args: never) => unknown;
|
||||
type D = (...args: never[]) => unknown;
|
||||
|
||||
type FnTypes = A | B | C | D;
|
||||
|
||||
function fx1(f: (() => void) | undefined) {
|
||||
if (isFunction<A>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx2(f: (() => void) | undefined) {
|
||||
if (isFunction<B>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx3(f: (() => void) | undefined) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function fx4(f: (() => void) | undefined) {
|
||||
if (isFunction<D>(f)) {
|
||||
f; // () => void
|
||||
}
|
||||
else {
|
||||
f; // undefined
|
||||
}
|
||||
f; // (() => void) | undefined
|
||||
}
|
||||
|
||||
function checkA(f: FnTypes) {
|
||||
if (isFunction<A>(f)) {
|
||||
f; // A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkB(f: FnTypes) {
|
||||
if (isFunction<B>(f)) {
|
||||
f; // A | B
|
||||
}
|
||||
else {
|
||||
f; // C | D
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkC(f: FnTypes) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
function checkD(f: FnTypes) {
|
||||
if (isFunction<C>(f)) {
|
||||
f; // FnTypes
|
||||
}
|
||||
else {
|
||||
f; // never
|
||||
}
|
||||
f; // FnTypes
|
||||
}
|
||||
|
||||
// Type of x = y is y with freshness preserved
|
||||
|
||||
function fx10(obj1: { x?: number }, obj2: { x?: number, y?: number }) {
|
||||
obj1 = obj2 = { x: 1, y: 2 };
|
||||
obj2 = obj1 = { x: 1, y: 2 };
|
||||
}
|
||||
|
||||
function fx11(): { x?: number } {
|
||||
let obj: { x?: number, y?: number };
|
||||
return obj = { x: 1, y: 2 };
|
||||
}
|
||||
Reference in New Issue
Block a user