mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Improve checking of in operator (#50666)
* Improve checking of `in` operator
* Accept new baselines
* Add tests
* Delete old and accept new baselines
* Disallow right operand of type '{}'
* Accept new baselines
* Support number and symbol literals
* Add tests
* Disallow {} typed right operand only in strictNullChecks mode
* Accept new baselines
* Detect {} resulting from intersections
* Accept new baselines
* Don't attempt to reduce intersections with Record<K, unknown>
* Accept new baselines
* Return undefined instead of unknownSymbol from getGlobalRecordSymbol()
This commit is contained in:
parent
67f2b62ed2
commit
a11c41621b
@ -858,7 +858,8 @@ namespace ts {
|
||||
emptyTypeLiteralSymbol.members = createSymbolTable();
|
||||
const emptyTypeLiteralType = createAnonymousType(emptyTypeLiteralSymbol, emptySymbols, emptyArray, emptyArray, emptyArray);
|
||||
|
||||
const unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray)]) : unknownType;
|
||||
const unknownEmptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray);
|
||||
const unknownUnionType = strictNullChecks ? getUnionType([undefinedType, nullType, unknownEmptyObjectType]) : unknownType;
|
||||
|
||||
const emptyGenericType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, emptyArray) as ObjectType as GenericType;
|
||||
emptyGenericType.instantiations = new Map<string, TypeReference>();
|
||||
@ -998,6 +999,7 @@ namespace ts {
|
||||
let deferredGlobalOmitSymbol: Symbol | undefined;
|
||||
let deferredGlobalAwaitedSymbol: Symbol | undefined;
|
||||
let deferredGlobalBigIntType: ObjectType | undefined;
|
||||
let deferredGlobalRecordSymbol: Symbol | undefined;
|
||||
|
||||
const allPotentiallyUnusedIdentifiers = new Map<Path, PotentiallyUnusedIdentifier[]>(); // key is file name
|
||||
|
||||
@ -14314,6 +14316,11 @@ namespace ts {
|
||||
return (deferredGlobalBigIntType ||= getGlobalType("BigInt" as __String, /*arity*/ 0, /*reportErrors*/ false)) || emptyObjectType;
|
||||
}
|
||||
|
||||
function getGlobalRecordSymbol(): Symbol | undefined {
|
||||
deferredGlobalRecordSymbol ||= getGlobalTypeAliasSymbol("Record" as __String, /*arity*/ 2, /*reportErrors*/ true) || unknownSymbol;
|
||||
return deferredGlobalRecordSymbol === unknownSymbol ? undefined : deferredGlobalRecordSymbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a global type that is generic with some element type, and returns that instantiation.
|
||||
*/
|
||||
@ -25199,19 +25206,27 @@ namespace ts {
|
||||
|
||||
function isTypePresencePossible(type: Type, propName: __String, assumeTrue: boolean) {
|
||||
const prop = getPropertyOfType(type, propName);
|
||||
if (prop) {
|
||||
return prop.flags & SymbolFlags.Optional ? true : assumeTrue;
|
||||
}
|
||||
return getApplicableIndexInfoForName(type, propName) ? true : !assumeTrue;
|
||||
return prop ?
|
||||
!!(prop.flags & SymbolFlags.Optional) || assumeTrue :
|
||||
!!getApplicableIndexInfoForName(type, propName) || !assumeTrue;
|
||||
}
|
||||
|
||||
function narrowByInKeyword(type: Type, name: __String, assumeTrue: boolean) {
|
||||
if (type.flags & TypeFlags.Union
|
||||
|| type.flags & TypeFlags.Object && declaredType !== type && !(declaredType === unknownType && isEmptyAnonymousObjectType(type))
|
||||
|| isThisTypeParameter(type)
|
||||
|| type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, t => t.symbol !== globalThisSymbol)) {
|
||||
function narrowByInKeyword(type: Type, nameType: StringLiteralType | NumberLiteralType | UniqueESSymbolType, assumeTrue: boolean) {
|
||||
const name = getPropertyNameFromType(nameType);
|
||||
const isKnownProperty = someType(type, t => isTypePresencePossible(t, name, /*assumeTrue*/ true));
|
||||
if (isKnownProperty) {
|
||||
// If the check is for a known property (i.e. a property declared in some constituent of
|
||||
// the target type), we filter the target type by presence of absence of the property.
|
||||
return filterType(type, t => isTypePresencePossible(t, name, assumeTrue));
|
||||
}
|
||||
if (assumeTrue) {
|
||||
// If the check is for an unknown property, we intersect the target type with `Record<X, unknown>`,
|
||||
// where X is the name of the property.
|
||||
const recordSymbol = getGlobalRecordSymbol();
|
||||
if (recordSymbol) {
|
||||
return getIntersectionType([type, getTypeAliasInstantiation(recordSymbol, [nameType, unknownType])]);
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -25271,15 +25286,14 @@ namespace ts {
|
||||
return narrowTypeByPrivateIdentifierInInExpression(type, expr, assumeTrue);
|
||||
}
|
||||
const target = getReferenceCandidate(expr.right);
|
||||
const leftType = getTypeOfNode(expr.left);
|
||||
if (leftType.flags & TypeFlags.StringLiteral) {
|
||||
const name = escapeLeadingUnderscores((leftType as StringLiteralType).value);
|
||||
const leftType = getTypeOfExpression(expr.left);
|
||||
if (leftType.flags & TypeFlags.StringOrNumberLiteralOrUnique) {
|
||||
if (containsMissingType(type) && isAccessExpression(reference) && isMatchingReference(reference.expression, target) &&
|
||||
getAccessedPropertyName(reference) === name) {
|
||||
getAccessedPropertyName(reference) === getPropertyNameFromType(leftType as StringLiteralType | NumberLiteralType | UniqueESSymbolType)) {
|
||||
return getTypeWithFacts(type, assumeTrue ? TypeFacts.NEUndefined : TypeFacts.EQUndefined);
|
||||
}
|
||||
if (isMatchingReference(reference, target)) {
|
||||
return narrowByInKeyword(type, name, assumeTrue);
|
||||
return narrowByInKeyword(type, leftType as StringLiteralType | NumberLiteralType | UniqueESSymbolType, assumeTrue);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -33848,6 +33862,10 @@ namespace ts {
|
||||
return booleanType;
|
||||
}
|
||||
|
||||
function hasEmptyObjectIntersection(type: Type): boolean {
|
||||
return someType(type, t => t === unknownEmptyObjectType || !!(t.flags & TypeFlags.Intersection) && some((t as IntersectionType).types, isEmptyAnonymousObjectType));
|
||||
}
|
||||
|
||||
function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type {
|
||||
if (leftType === silentNeverType || rightType === silentNeverType) {
|
||||
return silentNeverType;
|
||||
@ -33864,43 +33882,20 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
leftType = checkNonNullType(leftType, left);
|
||||
// TypeScript 1.0 spec (April 2014): 4.15.5
|
||||
// Require the left operand to be of type Any, the String primitive type, or the Number primitive type.
|
||||
if (!(allTypesAssignableToKind(leftType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbolLike) ||
|
||||
isTypeAssignableToKind(leftType, TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping | TypeFlags.TypeParameter))) {
|
||||
error(left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_a_private_identifier_or_of_type_any_string_number_or_symbol);
|
||||
// The type of the lef operand must be assignable to string, number, or symbol.
|
||||
checkTypeAssignableTo(checkNonNullType(leftType, left), stringNumberSymbolType, left);
|
||||
}
|
||||
// The type of the right operand must be assignable to 'object'.
|
||||
if (checkTypeAssignableTo(checkNonNullType(rightType, right), nonPrimitiveType, right)) {
|
||||
// The {} type is assignable to the object type, yet {} might represent a primitive type. Here we
|
||||
// detect and error on {} that results from narrowing the unknown type, as well as intersections
|
||||
// that include {} (we know that the other types in such intersections are assignable to object
|
||||
// since we already checked for that).
|
||||
if (hasEmptyObjectIntersection(rightType)) {
|
||||
error(right, Diagnostics.Type_0_may_represent_a_primitive_value_which_is_not_permitted_as_the_right_operand_of_the_in_operator, typeToString(rightType));
|
||||
}
|
||||
}
|
||||
rightType = checkNonNullType(rightType, right);
|
||||
// TypeScript 1.0 spec (April 2014): 4.15.5
|
||||
// The in operator requires the right operand to be
|
||||
//
|
||||
// 1. assignable to the non-primitive type,
|
||||
// 2. an unconstrained type parameter,
|
||||
// 3. a union or intersection including one or more type parameters, whose constituents are all assignable to the
|
||||
// the non-primitive type, or are unconstrainted type parameters, or have constraints assignable to the
|
||||
// non-primitive type, or
|
||||
// 4. a type parameter whose constraint is
|
||||
// i. an object type,
|
||||
// ii. the non-primitive type, or
|
||||
// iii. a union or intersection with at least one constituent assignable to an object or non-primitive type.
|
||||
//
|
||||
// The divergent behavior for type parameters and unions containing type parameters is a workaround for type
|
||||
// parameters not being narrowable. If the right operand is a concrete type, we can error if there is any chance
|
||||
// it is a primitive. But if the operand is a type parameter, it cannot be narrowed, so we don't issue an error
|
||||
// unless *all* instantiations would result in an error.
|
||||
//
|
||||
// The result is always of the Boolean primitive type.
|
||||
const rightTypeConstraint = getConstraintOfType(rightType);
|
||||
if (!allTypesAssignableToKind(rightType, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
|
||||
rightTypeConstraint && (
|
||||
isTypeAssignableToKind(rightType, TypeFlags.UnionOrIntersection) && !allTypesAssignableToKind(rightTypeConstraint, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive) ||
|
||||
!maybeTypeOfKind(rightTypeConstraint, TypeFlags.NonPrimitive | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object)
|
||||
)
|
||||
) {
|
||||
error(right, Diagnostics.The_right_hand_side_of_an_in_expression_must_not_be_a_primitive);
|
||||
}
|
||||
return booleanType;
|
||||
}
|
||||
|
||||
|
||||
@ -1844,14 +1844,6 @@
|
||||
"category": "Error",
|
||||
"code": 2359
|
||||
},
|
||||
"The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.": {
|
||||
"category": "Error",
|
||||
"code": 2360
|
||||
},
|
||||
"The right-hand side of an 'in' expression must not be a primitive.": {
|
||||
"category": "Error",
|
||||
"code": 2361
|
||||
},
|
||||
"The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.": {
|
||||
"category": "Error",
|
||||
"code": 2362
|
||||
@ -2845,6 +2837,10 @@
|
||||
"category": "Error",
|
||||
"code": 2637
|
||||
},
|
||||
"Type '{0}' may represent a primitive value, which is not permitted as the right operand of the 'in' operator.": {
|
||||
"category": "Error",
|
||||
"code": 2638
|
||||
},
|
||||
|
||||
"Cannot augment module '{0}' with value exports because it resolves to a non-module entity.": {
|
||||
"category": "Error",
|
||||
|
||||
@ -0,0 +1,153 @@
|
||||
tests/cases/compiler/conditionalTypeDoesntSpinForever.ts(23,15): error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
tests/cases/compiler/conditionalTypeDoesntSpinForever.ts(36,19): error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
tests/cases/compiler/conditionalTypeDoesntSpinForever.ts(53,21): error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
tests/cases/compiler/conditionalTypeDoesntSpinForever.ts(53,45): error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
tests/cases/compiler/conditionalTypeDoesntSpinForever.ts(65,17): error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
tests/cases/compiler/conditionalTypeDoesntSpinForever.ts(78,38): error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
tests/cases/compiler/conditionalTypeDoesntSpinForever.ts(94,21): error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
tests/cases/compiler/conditionalTypeDoesntSpinForever.ts(97,71): error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/conditionalTypeDoesntSpinForever.ts (8 errors) ====
|
||||
// A *self-contained* demonstration of the problem follows...
|
||||
// Test this by running `tsc --target es6` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
|
||||
|
||||
export enum PubSubRecordIsStoredInRedisAsA {
|
||||
redisHash = "redisHash",
|
||||
jsonEncodedRedisString = "jsonEncodedRedisString"
|
||||
}
|
||||
|
||||
export interface PubSubRecord<NAME extends string, RECORD, IDENTIFIER extends Partial<RECORD>> {
|
||||
name: NAME;
|
||||
record: RECORD;
|
||||
identifier: IDENTIFIER;
|
||||
storedAs: PubSubRecordIsStoredInRedisAsA;
|
||||
maxMsToWaitBeforePublishing: number;
|
||||
}
|
||||
|
||||
type NameFieldConstructor<SO_FAR> =
|
||||
SO_FAR extends {name: any} ? {} : {
|
||||
name: <TYPE>(t?: TYPE) => BuildPubSubRecordType<SO_FAR & {name: TYPE}>
|
||||
}
|
||||
|
||||
const buildNameFieldConstructor = <SO_FAR>(soFar: SO_FAR) => (
|
||||
"name" in soFar ? {} : {
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/conditionalTypeDoesntSpinForever.ts:22:38: This type parameter might need an `extends object` constraint.
|
||||
name: <TYPE>(instance: TYPE = undefined) =>
|
||||
buildPubSubRecordType(Object.assign({}, soFar, {name: instance as TYPE}) as SO_FAR & {name: TYPE}) as BuildPubSubRecordType<SO_FAR & {name: TYPE}>
|
||||
}
|
||||
);
|
||||
|
||||
type StoredAsConstructor<SO_FAR> =
|
||||
SO_FAR extends {storedAs: any} ? {} : {
|
||||
storedAsJsonEncodedRedisString: () => BuildPubSubRecordType<SO_FAR & {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString}>;
|
||||
storedRedisHash: () => BuildPubSubRecordType<SO_FAR & {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash}>;
|
||||
}
|
||||
|
||||
const buildStoredAsConstructor = <SO_FAR>(soFar: SO_FAR) => (
|
||||
"storedAs" in soFar ? {} : {
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/conditionalTypeDoesntSpinForever.ts:35:37: This type parameter might need an `extends object` constraint.
|
||||
storedAsJsonEncodedRedisString: () =>
|
||||
buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString})) as
|
||||
BuildPubSubRecordType<SO_FAR & {storedAs: PubSubRecordIsStoredInRedisAsA.jsonEncodedRedisString}>,
|
||||
storedAsRedisHash: () =>
|
||||
buildPubSubRecordType(Object.assign({}, soFar, {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash})) as
|
||||
BuildPubSubRecordType<SO_FAR & {storedAs: PubSubRecordIsStoredInRedisAsA.redisHash}>,
|
||||
}
|
||||
);
|
||||
|
||||
type IdentifierFieldConstructor<SO_FAR> =
|
||||
SO_FAR extends {identifier: any} ? {} :
|
||||
SO_FAR extends {record: any} ? {
|
||||
identifier: <TYPE extends Partial<SO_FAR["record"]>>(t?: TYPE) => BuildPubSubRecordType<SO_FAR & {identifier: TYPE}>
|
||||
} : {}
|
||||
|
||||
const buildIdentifierFieldConstructor = <SO_FAR>(soFar: SO_FAR) => (
|
||||
"identifier" in soFar || (!("record" in soFar)) ? {} : {
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/conditionalTypeDoesntSpinForever.ts:52:44: This type parameter might need an `extends object` constraint.
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/conditionalTypeDoesntSpinForever.ts:52:44: This type parameter might need an `extends object` constraint.
|
||||
identifier: <TYPE>(instance: TYPE = undefined) =>
|
||||
buildPubSubRecordType(Object.assign({}, soFar, {identifier: instance as TYPE}) as SO_FAR & {identifier: TYPE}) as BuildPubSubRecordType<SO_FAR & {identifier: TYPE}>
|
||||
}
|
||||
);
|
||||
|
||||
type RecordFieldConstructor<SO_FAR> =
|
||||
SO_FAR extends {record: any} ? {} : {
|
||||
record: <TYPE>(t?: TYPE) => BuildPubSubRecordType<SO_FAR & {record: TYPE}>
|
||||
}
|
||||
|
||||
const buildRecordFieldConstructor = <SO_FAR>(soFar: SO_FAR) => (
|
||||
"record" in soFar ? {} : {
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/conditionalTypeDoesntSpinForever.ts:64:40: This type parameter might need an `extends object` constraint.
|
||||
record: <TYPE>(instance: TYPE = undefined) =>
|
||||
buildPubSubRecordType(Object.assign({}, soFar, {record: instance as TYPE}) as SO_FAR & {record: TYPE}) as BuildPubSubRecordType<SO_FAR & {record: TYPE}>
|
||||
}
|
||||
);
|
||||
|
||||
type MaxMsToWaitBeforePublishingFieldConstructor<SO_FAR> =
|
||||
SO_FAR extends {maxMsToWaitBeforePublishing: any} ? {} : {
|
||||
maxMsToWaitBeforePublishing: (t: number) => BuildPubSubRecordType<SO_FAR & {maxMsToWaitBeforePublishing: number}>,
|
||||
neverDelayPublishing: () => BuildPubSubRecordType<SO_FAR & {maxMsToWaitBeforePublishing: 0}>,
|
||||
}
|
||||
|
||||
const buildMaxMsToWaitBeforePublishingFieldConstructor = <SO_FAR>(soFar: SO_FAR): MaxMsToWaitBeforePublishingFieldConstructor<SO_FAR> => (
|
||||
"maxMsToWaitBeforePublishing" in soFar ? {} : {
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/conditionalTypeDoesntSpinForever.ts:77:61: This type parameter might need an `extends object` constraint.
|
||||
maxMsToWaitBeforePublishing: (instance: number = 0) =>
|
||||
buildPubSubRecordType(Object.assign({}, soFar, {maxMsToWaitBeforePublishing: instance})) as BuildPubSubRecordType<SO_FAR & {maxMsToWaitBeforePublishing: number}>,
|
||||
neverDelayPublishing: () =>
|
||||
buildPubSubRecordType(Object.assign({}, soFar, {maxMsToWaitBeforePublishing: 0})) as BuildPubSubRecordType<SO_FAR & {maxMsToWaitBeforePublishing: 0}>,
|
||||
}
|
||||
) as MaxMsToWaitBeforePublishingFieldConstructor<SO_FAR>;
|
||||
|
||||
type TypeConstructor<SO_FAR> =
|
||||
SO_FAR extends {identifier: any, record: any, maxMsToWaitBeforePublishing: number, storedAs: PubSubRecordIsStoredInRedisAsA} ? {
|
||||
type: SO_FAR,
|
||||
fields: Set<keyof SO_FAR>,
|
||||
hasField: (fieldName: string | number | symbol) => fieldName is keyof SO_FAR
|
||||
} : {}
|
||||
|
||||
const buildType = <SO_FAR>(soFar: SO_FAR) => (
|
||||
"identifier" in soFar && "object" in soFar && "maxMsToWaitBeforePublishing" in soFar && "PubSubRecordIsStoredInRedisAsA" in soFar ? {} : {
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/conditionalTypeDoesntSpinForever.ts:93:22: This type parameter might need an `extends object` constraint.
|
||||
type: soFar,
|
||||
fields: () => new Set(Object.keys(soFar) as (keyof SO_FAR)[]),
|
||||
hasField: (fieldName: string | number | symbol) => fieldName in soFar
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'SO_FAR' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/conditionalTypeDoesntSpinForever.ts:93:22: This type parameter might need an `extends object` constraint.
|
||||
}
|
||||
);
|
||||
|
||||
type BuildPubSubRecordType<SO_FAR> =
|
||||
NameFieldConstructor<SO_FAR> &
|
||||
IdentifierFieldConstructor<SO_FAR> &
|
||||
RecordFieldConstructor<SO_FAR> &
|
||||
StoredAsConstructor<SO_FAR> & // infinite loop goes away when you comment out this line
|
||||
MaxMsToWaitBeforePublishingFieldConstructor<SO_FAR> &
|
||||
TypeConstructor<SO_FAR>
|
||||
|
||||
const buildPubSubRecordType = <SO_FAR>(soFar: SO_FAR) => Object.assign(
|
||||
{},
|
||||
buildNameFieldConstructor(soFar),
|
||||
buildIdentifierFieldConstructor(soFar),
|
||||
buildRecordFieldConstructor(soFar),
|
||||
buildStoredAsConstructor(soFar),
|
||||
buildMaxMsToWaitBeforePublishingFieldConstructor(soFar),
|
||||
buildType(soFar)
|
||||
) as BuildPubSubRecordType<SO_FAR>;
|
||||
const PubSubRecordType = buildPubSubRecordType({});
|
||||
@ -212,12 +212,12 @@ export enum PubSubRecordIsStoredInRedisAsA {
|
||||
>buildPubSubRecordType(Object.assign({}, soFar, {identifier: instance as TYPE}) as SO_FAR & {identifier: TYPE}) : BuildPubSubRecordType<SO_FAR & { identifier: TYPE; }>
|
||||
>buildPubSubRecordType : <SO_FAR>(soFar: SO_FAR) => BuildPubSubRecordType<SO_FAR>
|
||||
>Object.assign({}, soFar, {identifier: instance as TYPE}) as SO_FAR & {identifier: TYPE} : SO_FAR & { identifier: TYPE; }
|
||||
>Object.assign({}, soFar, {identifier: instance as TYPE}) : SO_FAR & { identifier: TYPE; }
|
||||
>Object.assign({}, soFar, {identifier: instance as TYPE}) : SO_FAR & Record<"record", unknown> & { identifier: TYPE; }
|
||||
>Object.assign : { <T extends {}, U>(target: T, source: U): T & U; <T extends {}, U, V>(target: T, source1: U, source2: V): T & U & V; <T extends {}, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
|
||||
>Object : ObjectConstructor
|
||||
>assign : { <T extends {}, U>(target: T, source: U): T & U; <T extends {}, U, V>(target: T, source1: U, source2: V): T & U & V; <T extends {}, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
|
||||
>{} : {}
|
||||
>soFar : SO_FAR
|
||||
>soFar : SO_FAR & Record<"record", unknown>
|
||||
>{identifier: instance as TYPE} : { identifier: TYPE; }
|
||||
>identifier : TYPE
|
||||
>instance as TYPE : TYPE
|
||||
@ -389,13 +389,13 @@ export enum PubSubRecordIsStoredInRedisAsA {
|
||||
>soFar : SO_FAR
|
||||
>"object" in soFar : boolean
|
||||
>"object" : "object"
|
||||
>soFar : SO_FAR
|
||||
>soFar : SO_FAR & Record<"identifier", unknown>
|
||||
>"maxMsToWaitBeforePublishing" in soFar : boolean
|
||||
>"maxMsToWaitBeforePublishing" : "maxMsToWaitBeforePublishing"
|
||||
>soFar : SO_FAR
|
||||
>soFar : SO_FAR & Record<"identifier", unknown> & Record<"object", unknown>
|
||||
>"PubSubRecordIsStoredInRedisAsA" in soFar : boolean
|
||||
>"PubSubRecordIsStoredInRedisAsA" : "PubSubRecordIsStoredInRedisAsA"
|
||||
>soFar : SO_FAR
|
||||
>soFar : SO_FAR & Record<"identifier", unknown> & Record<"object", unknown> & Record<"maxMsToWaitBeforePublishing", unknown>
|
||||
>{} : {}
|
||||
>{ type: soFar, fields: () => new Set(Object.keys(soFar) as (keyof SO_FAR)[]), hasField: (fieldName: string | number | symbol) => fieldName in soFar } : { type: SO_FAR; fields: () => Set<keyof SO_FAR>; hasField: (fieldName: string | number | symbol) => boolean; }
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ if ('d' in c) {
|
||||
>c : A | B
|
||||
|
||||
c; // never
|
||||
>c : never
|
||||
>c : (A | B) & Record<"d", unknown>
|
||||
}
|
||||
|
||||
if (a in c) {
|
||||
@ -67,6 +67,6 @@ if (d in c) {
|
||||
>c : A | B
|
||||
|
||||
c; // never
|
||||
>c : never
|
||||
>c : (A | B) & Record<"d", unknown>
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ tests/cases/conformance/fixSignatureCaching.ts(284,10): error TS2339: Property '
|
||||
tests/cases/conformance/fixSignatureCaching.ts(293,10): error TS2339: Property 'FALLBACK_PHONE' does not exist on type '{}'.
|
||||
tests/cases/conformance/fixSignatureCaching.ts(294,10): error TS2339: Property 'FALLBACK_TABLET' does not exist on type '{}'.
|
||||
tests/cases/conformance/fixSignatureCaching.ts(295,10): error TS2339: Property 'FALLBACK_MOBILE' does not exist on type '{}'.
|
||||
tests/cases/conformance/fixSignatureCaching.ts(301,17): error TS2339: Property 'isArray' does not exist on type 'never'.
|
||||
tests/cases/conformance/fixSignatureCaching.ts(330,74): error TS2339: Property 'mobileDetectRules' does not exist on type '{}'.
|
||||
tests/cases/conformance/fixSignatureCaching.ts(369,10): error TS2339: Property 'findMatch' does not exist on type '{}'.
|
||||
tests/cases/conformance/fixSignatureCaching.ts(387,10): error TS2339: Property 'findMatches' does not exist on type '{}'.
|
||||
@ -58,7 +59,7 @@ tests/cases/conformance/fixSignatureCaching.ts(981,16): error TS2304: Cannot fin
|
||||
tests/cases/conformance/fixSignatureCaching.ts(983,44): error TS2339: Property 'MobileDetect' does not exist on type 'Window & typeof globalThis'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/fixSignatureCaching.ts (58 errors) ====
|
||||
==== tests/cases/conformance/fixSignatureCaching.ts (59 errors) ====
|
||||
// Repro from #10697
|
||||
|
||||
(function (define, undefined) {
|
||||
@ -370,6 +371,8 @@ tests/cases/conformance/fixSignatureCaching.ts(983,44): error TS2339: Property '
|
||||
isArray = 'isArray' in Array
|
||||
? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; }
|
||||
: Array.isArray;
|
||||
~~~~~~~
|
||||
!!! error TS2339: Property 'isArray' does not exist on type 'never'.
|
||||
|
||||
function equalIC(a, b) {
|
||||
return a != null && b != null && a.toLowerCase() === b.toLowerCase();
|
||||
|
||||
@ -825,9 +825,7 @@ define(function () {
|
||||
>value : Symbol(value, Decl(fixSignatureCaching.ts, 299, 20))
|
||||
|
||||
: Array.isArray;
|
||||
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
function equalIC(a, b) {
|
||||
>equalIC : Symbol(equalIC, Decl(fixSignatureCaching.ts, 300, 24))
|
||||
|
||||
@ -1127,9 +1127,9 @@ define(function () {
|
||||
>'[object Array]' : "[object Array]"
|
||||
|
||||
isArray = 'isArray' in Array
|
||||
>isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : (value: any) => boolean
|
||||
>isArray = 'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : any
|
||||
>isArray : any
|
||||
>'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : (value: any) => boolean
|
||||
>'isArray' in Array ? function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : Array.isArray : any
|
||||
>'isArray' in Array : boolean
|
||||
>'isArray' : "isArray"
|
||||
>Array : ArrayConstructor
|
||||
@ -1150,9 +1150,9 @@ define(function () {
|
||||
>'[object Array]' : "[object Array]"
|
||||
|
||||
: Array.isArray;
|
||||
>Array.isArray : (arg: any) => arg is any[]
|
||||
>Array : ArrayConstructor
|
||||
>isArray : (arg: any) => arg is any[]
|
||||
>Array.isArray : any
|
||||
>Array : never
|
||||
>isArray : any
|
||||
|
||||
function equalIC(a, b) {
|
||||
>equalIC : (a: any, b: any) => boolean
|
||||
|
||||
@ -1,13 +1,31 @@
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(19,17): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(23,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(27,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(34,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(53,14): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(60,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(12,17): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(19,17): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
Type 'string | number' is not assignable to type 'object'.
|
||||
Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(23,12): error TS2322: Type 'T | U' is not assignable to type 'object'.
|
||||
Type 'T' is not assignable to type 'object'.
|
||||
Type 'string | number' is not assignable to type 'object'.
|
||||
Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(27,12): error TS2322: Type 'T | U' is not assignable to type 'object'.
|
||||
Type 'U' is not assignable to type 'object'.
|
||||
Type 'string | number' is not assignable to type 'object'.
|
||||
Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(34,12): error TS2322: Type 'string | number | T' is not assignable to type 'object'.
|
||||
Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(36,14): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(41,12): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
Type 'object | "hello"' is not assignable to type 'object'.
|
||||
Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(53,14): error TS2322: Type 'T | U' is not assignable to type 'object'.
|
||||
Type 'T' is not assignable to type 'object'.
|
||||
Type 'string | object' is not assignable to type 'object'.
|
||||
Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(60,12): error TS2322: Type 'T & U' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2322: Type 'T & (0 | 1 | 2)' is not assignable to type 'object'.
|
||||
Type 'T & 0' is not assignable to type 'object'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts (7 errors) ====
|
||||
==== tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts (10 errors) ====
|
||||
const validHasKey = <T extends object>(
|
||||
thing: T,
|
||||
key: string,
|
||||
@ -20,6 +38,9 @@ tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2361: T
|
||||
key: string,
|
||||
): boolean => {
|
||||
return key in thing; // Ok (as T may be instantiated with a valid type)
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts:8:26: This type parameter might need an `extends object` constraint.
|
||||
};
|
||||
|
||||
function invalidHasKey<T extends string | number>(
|
||||
@ -28,19 +49,27 @@ tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2361: T
|
||||
): boolean {
|
||||
return key in thing; // Error (because all possible instantiations are errors)
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
}
|
||||
|
||||
function union1<T extends string | number, U extends boolean>(thing: T | U) {
|
||||
"key" in thing; // Error (because all possible instantiations are errors)
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'T | U' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
}
|
||||
|
||||
function union2<T extends object, U extends string | number>(thing: T | U) {
|
||||
"key" in thing; // Error (because narrowing is possible)
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'T | U' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'U' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
if (typeof thing === "object") {
|
||||
"key" in thing; // Ok
|
||||
}
|
||||
@ -49,14 +78,22 @@ tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2361: T
|
||||
function union3<T>(thing: T | string | number) {
|
||||
"key" in thing; // Error (because narrowing is possible)
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'string | number | T' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
if (typeof thing !== "string" && typeof thing !== "number") {
|
||||
"key" in thing; // Ok (because further narrowing is impossible)
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts:33:17: This type parameter might need an `extends object` constraint.
|
||||
}
|
||||
}
|
||||
|
||||
function union4<T extends object | "hello">(thing: T) {
|
||||
"key" in thing; // Ok (because narrowing is impossible)
|
||||
~~~~~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'object | "hello"' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
}
|
||||
|
||||
function union5<T extends object | string, U extends object | number>(p: T | U) {
|
||||
@ -70,7 +107,10 @@ tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2361: T
|
||||
// error seems very low-value.
|
||||
"key" in p;
|
||||
~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'T | U' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string | object' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
if (typeof p === "object") {
|
||||
"key" in p;
|
||||
}
|
||||
@ -79,12 +119,13 @@ tests/cases/compiler/inDoesNotOperateOnPrimitiveTypes.ts(64,12): error TS2361: T
|
||||
function intersection1<T extends number, U extends 0 | 1 | 2>(thing: T & U) {
|
||||
"key" in thing; // Error (because all possible instantiations are errors)
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'T & U' is not assignable to type 'object'.
|
||||
}
|
||||
|
||||
function intersection2<T>(thing: T & (0 | 1 | 2)) {
|
||||
"key" in thing; // Error (because all possible instantations are errors)
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'T & (0 | 1 | 2)' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T & 0' is not assignable to type 'object'.
|
||||
}
|
||||
|
||||
23
tests/baselines/reference/inKeywordAndUnknown.errors.txt
Normal file
23
tests/baselines/reference/inKeywordAndUnknown.errors.txt
Normal file
@ -0,0 +1,23 @@
|
||||
tests/cases/compiler/inKeywordAndUnknown.ts(12,18): error TS2638: Type '{}' may represent a primitive value, which is not permitted as the right operand of the 'in' operator.
|
||||
|
||||
|
||||
==== tests/cases/compiler/inKeywordAndUnknown.ts (1 errors) ====
|
||||
// Repro from #50531
|
||||
|
||||
function f(x: {}, y: unknown) {
|
||||
if (!("a" in x)) {
|
||||
return;
|
||||
}
|
||||
x; // {}
|
||||
if (!y) {
|
||||
return;
|
||||
}
|
||||
y; // {}
|
||||
if (!("a" in y)) {
|
||||
~
|
||||
!!! error TS2638: Type '{}' may represent a primitive value, which is not permitted as the right operand of the 'in' operator.
|
||||
return;
|
||||
}
|
||||
y; // {}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ function f(x: {}, y: unknown) {
|
||||
return;
|
||||
}
|
||||
x; // {}
|
||||
>x : {}
|
||||
>x : Record<"a", unknown>
|
||||
|
||||
if (!y) {
|
||||
>!y : boolean
|
||||
@ -37,6 +37,6 @@ function f(x: {}, y: unknown) {
|
||||
return;
|
||||
}
|
||||
y; // {}
|
||||
>y : {}
|
||||
>y : Record<"a", unknown>
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,10 @@ tests/cases/compiler/inKeywordTypeguard.ts(16,11): error TS2339: Property 'a' do
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(27,11): error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'.
|
||||
Property 'b' does not exist on type 'AWithOptionalProp'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(42,11): error TS2339: Property 'b' does not exist on type 'AWithMethod'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(49,11): error TS2339: Property 'a' does not exist on type 'never'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(50,11): error TS2339: Property 'b' does not exist on type 'never'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(49,11): error TS2339: Property 'a' does not exist on type '(AWithMethod | BWithMethod) & Record<"c", unknown>'.
|
||||
Property 'a' does not exist on type 'BWithMethod & Record<"c", unknown>'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(50,11): error TS2339: Property 'b' does not exist on type '(AWithMethod | BWithMethod) & Record<"c", unknown>'.
|
||||
Property 'b' does not exist on type 'AWithMethod & Record<"c", unknown>'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(52,11): error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'.
|
||||
Property 'a' does not exist on type 'BWithMethod'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(53,11): error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'.
|
||||
@ -19,9 +21,14 @@ tests/cases/compiler/inKeywordTypeguard.ts(74,32): error TS2339: Property 'a' do
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(82,39): error TS2339: Property 'b' does not exist on type 'A'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(84,39): error TS2339: Property 'a' does not exist on type 'B'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' does not exist on type 'never'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(150,16): error TS2339: Property 'ontouchstart' does not exist on type 'never'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(155,16): error TS2322: Type 'unknown' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(158,21): error TS2322: Type 'unknown' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(183,16): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(186,21): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/inKeywordTypeguard.ts (17 errors) ====
|
||||
==== tests/cases/compiler/inKeywordTypeguard.ts (22 errors) ====
|
||||
class A { a: string; }
|
||||
class B { b: string; }
|
||||
|
||||
@ -85,10 +92,12 @@ tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' do
|
||||
if ("c" in x) {
|
||||
x.a();
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'never'.
|
||||
!!! error TS2339: Property 'a' does not exist on type '(AWithMethod | BWithMethod) & Record<"c", unknown>'.
|
||||
!!! error TS2339: Property 'a' does not exist on type 'BWithMethod & Record<"c", unknown>'.
|
||||
x.b();
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'never'.
|
||||
!!! error TS2339: Property 'b' does not exist on type '(AWithMethod | BWithMethod) & Record<"c", unknown>'.
|
||||
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod & Record<"c", unknown>'.
|
||||
} else {
|
||||
x.a();
|
||||
~
|
||||
@ -210,6 +219,145 @@ tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' do
|
||||
window.ontouchstart
|
||||
} else {
|
||||
window.ontouchstart
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'ontouchstart' does not exist on type 'never'.
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
if ("a" in x) {
|
||||
~
|
||||
!!! error TS2322: Type 'unknown' is not assignable to type 'object'.
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
~
|
||||
!!! error TS2322: Type 'unknown' is not assignable to type 'object'.
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
if ("a" in x) {
|
||||
~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/inKeywordTypeguard.ts:182:13: This type parameter might need an `extends object` constraint.
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/inKeywordTypeguard.ts:182:13: This type parameter might need an `extends object` constraint.
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
x; // { b: string }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
if ("a" in x) {
|
||||
x;
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if ("a" in y) {
|
||||
y;
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
|
||||
function f8(x: object) {
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
|
||||
541
tests/baselines/reference/inKeywordTypeguard(strict=false).js
Normal file
541
tests/baselines/reference/inKeywordTypeguard(strict=false).js
Normal file
@ -0,0 +1,541 @@
|
||||
//// [inKeywordTypeguard.ts]
|
||||
class A { a: string; }
|
||||
class B { b: string; }
|
||||
|
||||
function negativeClassesTest(x: A | B) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
function positiveClassesTest(x: A | B) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class AWithOptionalProp { a?: string; }
|
||||
class BWithOptionalProp { b?: string; }
|
||||
|
||||
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
|
||||
if ("a" in x) {
|
||||
x.a = "1";
|
||||
} else {
|
||||
x.b = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class AWithMethod {
|
||||
a(): string { return ""; }
|
||||
}
|
||||
|
||||
class BWithMethod {
|
||||
b(): string { return ""; }
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
|
||||
if ("a" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
|
||||
if ("c" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
} else {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
}
|
||||
|
||||
class C { a: string; }
|
||||
class D { a: string; }
|
||||
|
||||
function negativeMultipleClassesTest(x: A | B | C | D) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class ClassWithUnionProp { prop: A | B }
|
||||
|
||||
function negativePropTest(x: ClassWithUnionProp) {
|
||||
if ("a" in x.prop) {
|
||||
let y: string = x.prop.b;
|
||||
} else {
|
||||
let z: string = x.prop.a;
|
||||
}
|
||||
}
|
||||
|
||||
class NegativeClassTest {
|
||||
protected prop: A | B;
|
||||
inThis() {
|
||||
if ("a" in this.prop) {
|
||||
let z: number = this.prop.b;
|
||||
} else {
|
||||
let y: string = this.prop.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnreachableCodeDetection {
|
||||
a: string;
|
||||
inThis() {
|
||||
if ("a" in this) {
|
||||
} else {
|
||||
let y = this.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positiveIntersectionTest(x: { a: string } & { b: string }) {
|
||||
if ("a" in x) {
|
||||
let s: string = x.a;
|
||||
} else {
|
||||
let n: never = x;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38608
|
||||
declare const error: Error;
|
||||
if ('extra' in error) {
|
||||
error // Still Error
|
||||
} else {
|
||||
error // Error
|
||||
}
|
||||
|
||||
function narrowsToNever(x: { l: number } | { r: number }) {
|
||||
let v: number;
|
||||
if ("l" in x) {
|
||||
v = x.l;
|
||||
}
|
||||
else if ("r" in x) {
|
||||
v = x.r;
|
||||
}
|
||||
else {
|
||||
v = x
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
type AOrB = { aProp: number } | { bProp: number };
|
||||
declare function isAOrB(x: unknown): x is AOrB;
|
||||
|
||||
declare var x: unknown;
|
||||
if (isAOrB(x)) {
|
||||
if ("aProp" in x) {
|
||||
x.aProp;
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
x.bProp;
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
const _never: never = x;
|
||||
}
|
||||
}
|
||||
|
||||
function negativeIntersectionTest() {
|
||||
if ("ontouchstart" in window) {
|
||||
window.ontouchstart
|
||||
} else {
|
||||
window.ontouchstart
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
x; // { b: string }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
if ("a" in x) {
|
||||
x;
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if ("a" in y) {
|
||||
y;
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
|
||||
function f8(x: object) {
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [inKeywordTypeguard.js]
|
||||
class A {
|
||||
}
|
||||
class B {
|
||||
}
|
||||
function negativeClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
function positiveClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
class AWithOptionalProp {
|
||||
}
|
||||
class BWithOptionalProp {
|
||||
}
|
||||
function positiveTestClassesWithOptionalProperties(x) {
|
||||
if ("a" in x) {
|
||||
x.a = "1";
|
||||
}
|
||||
else {
|
||||
x.b = "1";
|
||||
}
|
||||
}
|
||||
class AWithMethod {
|
||||
a() { return ""; }
|
||||
}
|
||||
class BWithMethod {
|
||||
b() { return ""; }
|
||||
}
|
||||
function negativeTestClassesWithMembers(x) {
|
||||
if ("a" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x) {
|
||||
if ("c" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
else {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
}
|
||||
class C {
|
||||
}
|
||||
class D {
|
||||
}
|
||||
function negativeMultipleClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
class ClassWithUnionProp {
|
||||
}
|
||||
function negativePropTest(x) {
|
||||
if ("a" in x.prop) {
|
||||
let y = x.prop.b;
|
||||
}
|
||||
else {
|
||||
let z = x.prop.a;
|
||||
}
|
||||
}
|
||||
class NegativeClassTest {
|
||||
inThis() {
|
||||
if ("a" in this.prop) {
|
||||
let z = this.prop.b;
|
||||
}
|
||||
else {
|
||||
let y = this.prop.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
class UnreachableCodeDetection {
|
||||
inThis() {
|
||||
if ("a" in this) {
|
||||
}
|
||||
else {
|
||||
let y = this.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
function positiveIntersectionTest(x) {
|
||||
if ("a" in x) {
|
||||
let s = x.a;
|
||||
}
|
||||
else {
|
||||
let n = x;
|
||||
}
|
||||
}
|
||||
if ('extra' in error) {
|
||||
error; // Still Error
|
||||
}
|
||||
else {
|
||||
error; // Error
|
||||
}
|
||||
function narrowsToNever(x) {
|
||||
let v;
|
||||
if ("l" in x) {
|
||||
v = x.l;
|
||||
}
|
||||
else if ("r" in x) {
|
||||
v = x.r;
|
||||
}
|
||||
else {
|
||||
v = x;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
if (isAOrB(x)) {
|
||||
if ("aProp" in x) {
|
||||
x.aProp;
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
x.bProp;
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
const _never = x;
|
||||
}
|
||||
}
|
||||
function negativeIntersectionTest() {
|
||||
if ("ontouchstart" in window) {
|
||||
window.ontouchstart;
|
||||
}
|
||||
else {
|
||||
window.ontouchstart;
|
||||
}
|
||||
}
|
||||
function f1(x) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
function f2(x) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
function f3(x) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
function f4(x) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
function f5(x) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
x; // { b: string }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
}
|
||||
function f6(x) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
}
|
||||
}
|
||||
// Object and corresponding intersection should narrow the same
|
||||
function f7(x, y) {
|
||||
if ("a" in x) {
|
||||
x;
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if ("a" in y) {
|
||||
y;
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
}
|
||||
}
|
||||
const sym = Symbol();
|
||||
function f8(x) {
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
function f9(x) {
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
// Repro from #50639
|
||||
function foo(value) {
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
@ -371,9 +371,357 @@ function negativeIntersectionTest() {
|
||||
|
||||
} else {
|
||||
window.ontouchstart
|
||||
>window.ontouchstart : Symbol(ontouchstart, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||
>ontouchstart : Symbol(ontouchstart, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
>f1 : Symbol(f1, Decl(inKeywordTypeguard.ts, 151, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>a : Symbol(a)
|
||||
|
||||
x.b;
|
||||
>x.b : Symbol(b)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>b : Symbol(b)
|
||||
|
||||
x.c;
|
||||
>x.c : Symbol(c)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>c : Symbol(c)
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
>f2 : Symbol(f2, Decl(inKeywordTypeguard.ts, 168, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>a : Symbol(a)
|
||||
|
||||
x.b;
|
||||
>x.b : Symbol(b)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>b : Symbol(b)
|
||||
|
||||
x.c;
|
||||
>x.c : Symbol(c)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>c : Symbol(c)
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
>f3 : Symbol(f3, Decl(inKeywordTypeguard.ts, 179, 1))
|
||||
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 181, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 181, 12))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>a : Symbol(a)
|
||||
|
||||
x.b;
|
||||
>x.b : Symbol(b)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>b : Symbol(b)
|
||||
|
||||
x.c;
|
||||
>x.c : Symbol(c)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>c : Symbol(c)
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
>f4 : Symbol(f4, Decl(inKeywordTypeguard.ts, 196, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
|
||||
x.b;
|
||||
>x.b : Symbol(b)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>b : Symbol(b)
|
||||
|
||||
x.c;
|
||||
>x.c : Symbol(c)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>c : Symbol(c)
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
>f5 : Symbol(f5, Decl(inKeywordTypeguard.ts, 207, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 209, 16))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 209, 32))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
|
||||
x; // { a: string }
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
}
|
||||
else if ("b" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
|
||||
x; // { b: string }
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
>f6 : Symbol(f6, Decl(inKeywordTypeguard.ts, 219, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 221, 16))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 221, 32))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
|
||||
x; // { a: string }
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
}
|
||||
else if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
>f7 : Symbol(f7, Decl(inKeywordTypeguard.ts, 231, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 235, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 235, 16))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 235, 27))
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 235, 40))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 235, 45))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 235, 61))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 235, 12))
|
||||
|
||||
x;
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 235, 12))
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 235, 12))
|
||||
}
|
||||
if ("a" in y) {
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 235, 40))
|
||||
|
||||
y;
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 235, 40))
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 235, 40))
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
|
||||
|
||||
function f8(x: object) {
|
||||
>f8 : Symbol(f8, Decl(inKeywordTypeguard.ts, 250, 21))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>a : Symbol(a)
|
||||
|
||||
x["a"];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>"a" : Symbol(a)
|
||||
|
||||
x[1];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>1 : Symbol(1)
|
||||
|
||||
x["1"];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>"1" : Symbol(1)
|
||||
|
||||
x[sym];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
>f9 : Symbol(f9, Decl(inKeywordTypeguard.ts, 260, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>a : Symbol(a)
|
||||
|
||||
x["a"];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>"a" : Symbol(a)
|
||||
|
||||
x[1];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>1 : Symbol(1)
|
||||
|
||||
x["1"];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>"1" : Symbol(1)
|
||||
|
||||
x[sym];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
>foo : Symbol(foo, Decl(inKeywordTypeguard.ts, 270, 1))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 274, 13))
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 274, 13))
|
||||
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
}
|
||||
}
|
||||
|
||||
914
tests/baselines/reference/inKeywordTypeguard(strict=false).types
Normal file
914
tests/baselines/reference/inKeywordTypeguard(strict=false).types
Normal file
@ -0,0 +1,914 @@
|
||||
=== tests/cases/compiler/inKeywordTypeguard.ts ===
|
||||
class A { a: string; }
|
||||
>A : A
|
||||
>a : string
|
||||
|
||||
class B { b: string; }
|
||||
>B : B
|
||||
>b : string
|
||||
|
||||
function negativeClassesTest(x: A | B) {
|
||||
>negativeClassesTest : (x: A | B) => void
|
||||
>x : A | B
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
function positiveClassesTest(x: A | B) {
|
||||
>positiveClassesTest : (x: A | B) => void
|
||||
>x : A | B
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class AWithOptionalProp { a?: string; }
|
||||
>AWithOptionalProp : AWithOptionalProp
|
||||
>a : string
|
||||
|
||||
class BWithOptionalProp { b?: string; }
|
||||
>BWithOptionalProp : BWithOptionalProp
|
||||
>b : string
|
||||
|
||||
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
|
||||
>positiveTestClassesWithOptionalProperties : (x: AWithOptionalProp | BWithOptionalProp) => void
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : string
|
||||
>x : AWithOptionalProp
|
||||
>a : string
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class AWithMethod {
|
||||
>AWithMethod : AWithMethod
|
||||
|
||||
a(): string { return ""; }
|
||||
>a : () => string
|
||||
>"" : ""
|
||||
}
|
||||
|
||||
class BWithMethod {
|
||||
>BWithMethod : BWithMethod
|
||||
|
||||
b(): string { return ""; }
|
||||
>b : () => string
|
||||
>"" : ""
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
|
||||
>negativeTestClassesWithMembers : (x: AWithMethod | BWithMethod) => void
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
x.a();
|
||||
>x.a() : string
|
||||
>x.a : () => string
|
||||
>x : AWithMethod
|
||||
>a : () => string
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : AWithMethod
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
|
||||
>negativeTestClassesWithMemberMissingInBothClasses : (x: AWithMethod | BWithMethod) => void
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
if ("c" in x) {
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
x.a();
|
||||
>x.a() : any
|
||||
>x.a : any
|
||||
>x : (AWithMethod | BWithMethod) & Record<"c", unknown>
|
||||
>a : any
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : (AWithMethod | BWithMethod) & Record<"c", unknown>
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
x.a();
|
||||
>x.a() : any
|
||||
>x.a : any
|
||||
>x : AWithMethod | BWithMethod
|
||||
>a : any
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : AWithMethod | BWithMethod
|
||||
>b : any
|
||||
}
|
||||
}
|
||||
|
||||
class C { a: string; }
|
||||
>C : C
|
||||
>a : string
|
||||
|
||||
class D { a: string; }
|
||||
>D : D
|
||||
>a : string
|
||||
|
||||
function negativeMultipleClassesTest(x: A | B | C | D) {
|
||||
>negativeMultipleClassesTest : (x: A | B | C | D) => void
|
||||
>x : A | B | C | D
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B | C | D
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A | C | D
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class ClassWithUnionProp { prop: A | B }
|
||||
>ClassWithUnionProp : ClassWithUnionProp
|
||||
>prop : A | B
|
||||
|
||||
function negativePropTest(x: ClassWithUnionProp) {
|
||||
>negativePropTest : (x: ClassWithUnionProp) => void
|
||||
>x : ClassWithUnionProp
|
||||
|
||||
if ("a" in x.prop) {
|
||||
>"a" in x.prop : boolean
|
||||
>"a" : "a"
|
||||
>x.prop : A | B
|
||||
>x : ClassWithUnionProp
|
||||
>prop : A | B
|
||||
|
||||
let y: string = x.prop.b;
|
||||
>y : string
|
||||
>x.prop.b : any
|
||||
>x.prop : A
|
||||
>x : ClassWithUnionProp
|
||||
>prop : A
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
let z: string = x.prop.a;
|
||||
>z : string
|
||||
>x.prop.a : any
|
||||
>x.prop : B
|
||||
>x : ClassWithUnionProp
|
||||
>prop : B
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
|
||||
class NegativeClassTest {
|
||||
>NegativeClassTest : NegativeClassTest
|
||||
|
||||
protected prop: A | B;
|
||||
>prop : A | B
|
||||
|
||||
inThis() {
|
||||
>inThis : () => void
|
||||
|
||||
if ("a" in this.prop) {
|
||||
>"a" in this.prop : boolean
|
||||
>"a" : "a"
|
||||
>this.prop : A | B
|
||||
>this : this
|
||||
>prop : A | B
|
||||
|
||||
let z: number = this.prop.b;
|
||||
>z : number
|
||||
>this.prop.b : any
|
||||
>this.prop : A
|
||||
>this : this
|
||||
>prop : A
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
let y: string = this.prop.a;
|
||||
>y : string
|
||||
>this.prop.a : any
|
||||
>this.prop : B
|
||||
>this : this
|
||||
>prop : B
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnreachableCodeDetection {
|
||||
>UnreachableCodeDetection : UnreachableCodeDetection
|
||||
|
||||
a: string;
|
||||
>a : string
|
||||
|
||||
inThis() {
|
||||
>inThis : () => void
|
||||
|
||||
if ("a" in this) {
|
||||
>"a" in this : boolean
|
||||
>"a" : "a"
|
||||
>this : this
|
||||
|
||||
} else {
|
||||
let y = this.a;
|
||||
>y : any
|
||||
>this.a : any
|
||||
>this : never
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positiveIntersectionTest(x: { a: string } & { b: string }) {
|
||||
>positiveIntersectionTest : (x: { a: string;} & { b: string;}) => void
|
||||
>x : { a: string; } & { b: string; }
|
||||
>a : string
|
||||
>b : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; } & { b: string; }
|
||||
|
||||
let s: string = x.a;
|
||||
>s : string
|
||||
>x.a : string
|
||||
>x : { a: string; } & { b: string; }
|
||||
>a : string
|
||||
|
||||
} else {
|
||||
let n: never = x;
|
||||
>n : never
|
||||
>x : never
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38608
|
||||
declare const error: Error;
|
||||
>error : Error
|
||||
|
||||
if ('extra' in error) {
|
||||
>'extra' in error : boolean
|
||||
>'extra' : "extra"
|
||||
>error : Error
|
||||
|
||||
error // Still Error
|
||||
>error : Error & Record<"extra", unknown>
|
||||
|
||||
} else {
|
||||
error // Error
|
||||
>error : Error
|
||||
}
|
||||
|
||||
function narrowsToNever(x: { l: number } | { r: number }) {
|
||||
>narrowsToNever : (x: { l: number;} | { r: number;}) => number
|
||||
>x : { l: number; } | { r: number; }
|
||||
>l : number
|
||||
>r : number
|
||||
|
||||
let v: number;
|
||||
>v : number
|
||||
|
||||
if ("l" in x) {
|
||||
>"l" in x : boolean
|
||||
>"l" : "l"
|
||||
>x : { l: number; } | { r: number; }
|
||||
|
||||
v = x.l;
|
||||
>v = x.l : number
|
||||
>v : number
|
||||
>x.l : number
|
||||
>x : { l: number; }
|
||||
>l : number
|
||||
}
|
||||
else if ("r" in x) {
|
||||
>"r" in x : boolean
|
||||
>"r" : "r"
|
||||
>x : { r: number; }
|
||||
|
||||
v = x.r;
|
||||
>v = x.r : number
|
||||
>v : number
|
||||
>x.r : number
|
||||
>x : { r: number; }
|
||||
>r : number
|
||||
}
|
||||
else {
|
||||
v = x
|
||||
>v = x : never
|
||||
>v : number
|
||||
>x : never
|
||||
}
|
||||
return v;
|
||||
>v : number
|
||||
}
|
||||
|
||||
type AOrB = { aProp: number } | { bProp: number };
|
||||
>AOrB : { aProp: number; } | { bProp: number; }
|
||||
>aProp : number
|
||||
>bProp : number
|
||||
|
||||
declare function isAOrB(x: unknown): x is AOrB;
|
||||
>isAOrB : (x: unknown) => x is AOrB
|
||||
>x : unknown
|
||||
|
||||
declare var x: unknown;
|
||||
>x : unknown
|
||||
|
||||
if (isAOrB(x)) {
|
||||
>isAOrB(x) : boolean
|
||||
>isAOrB : (x: unknown) => x is AOrB
|
||||
>x : unknown
|
||||
|
||||
if ("aProp" in x) {
|
||||
>"aProp" in x : boolean
|
||||
>"aProp" : "aProp"
|
||||
>x : AOrB
|
||||
|
||||
x.aProp;
|
||||
>x.aProp : number
|
||||
>x : { aProp: number; }
|
||||
>aProp : number
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
>"bProp" in x : boolean
|
||||
>"bProp" : "bProp"
|
||||
>x : { bProp: number; }
|
||||
|
||||
x.bProp;
|
||||
>x.bProp : number
|
||||
>x : { bProp: number; }
|
||||
>bProp : number
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
>"cProp" in x : boolean
|
||||
>"cProp" : "cProp"
|
||||
>x : never
|
||||
|
||||
const _never: never = x;
|
||||
>_never : never
|
||||
>x : never
|
||||
}
|
||||
}
|
||||
|
||||
function negativeIntersectionTest() {
|
||||
>negativeIntersectionTest : () => void
|
||||
|
||||
if ("ontouchstart" in window) {
|
||||
>"ontouchstart" in window : boolean
|
||||
>"ontouchstart" : "ontouchstart"
|
||||
>window : Window & typeof globalThis
|
||||
|
||||
window.ontouchstart
|
||||
>window.ontouchstart : ((this: GlobalEventHandlers, ev: TouchEvent) => any) & ((this: Window, ev: TouchEvent) => any)
|
||||
>window : Window & typeof globalThis
|
||||
>ontouchstart : ((this: GlobalEventHandlers, ev: TouchEvent) => any) & ((this: Window, ev: TouchEvent) => any)
|
||||
|
||||
} else {
|
||||
window.ontouchstart
|
||||
>window.ontouchstart : any
|
||||
>window : never
|
||||
>ontouchstart : any
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
>f1 : (x: unknown) => void
|
||||
>x : unknown
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : unknown
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
>x && "a" in x : boolean
|
||||
>x : unknown
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : unknown
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
>x && typeof x === "object" && "a" in x : boolean
|
||||
>x && typeof x === "object" : boolean
|
||||
>x : unknown
|
||||
>typeof x === "object" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : unknown
|
||||
>"object" : "object"
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
>x && typeof x === "object" && "a" in x && "b" in x && "c" in x : boolean
|
||||
>x && typeof x === "object" && "a" in x && "b" in x : boolean
|
||||
>x && typeof x === "object" && "a" in x : boolean
|
||||
>x && typeof x === "object" : boolean
|
||||
>x : unknown
|
||||
>typeof x === "object" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : unknown
|
||||
>"object" : "object"
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : object & Record<"a", unknown>
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>a : unknown
|
||||
|
||||
x.b;
|
||||
>x.b : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>b : unknown
|
||||
|
||||
x.c;
|
||||
>x.c : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>c : unknown
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
>f2 : (x: object) => void
|
||||
>x : object
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
>"a" in x && "b" in x && "c" in x : boolean
|
||||
>"a" in x && "b" in x : boolean
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : object & Record<"a", unknown>
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>a : unknown
|
||||
|
||||
x.b;
|
||||
>x.b : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>b : unknown
|
||||
|
||||
x.c;
|
||||
>x.c : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>c : unknown
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
>f3 : <T>(x: T) => void
|
||||
>x : T
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : T
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : T & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
>x && "a" in x : boolean
|
||||
>x : T
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : T
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : T & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
>x && typeof x === "object" && "a" in x : boolean
|
||||
>x && typeof x === "object" : boolean
|
||||
>x : T
|
||||
>typeof x === "object" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : T
|
||||
>"object" : "object"
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : T & object
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : T & object & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
>x && typeof x === "object" && "a" in x && "b" in x && "c" in x : boolean
|
||||
>x && typeof x === "object" && "a" in x && "b" in x : boolean
|
||||
>x && typeof x === "object" && "a" in x : boolean
|
||||
>x && typeof x === "object" : boolean
|
||||
>x : T
|
||||
>typeof x === "object" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : T
|
||||
>"object" : "object"
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : T & object
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : T & object & Record<"a", unknown>
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : T & object & Record<"a", unknown> & Record<"b", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : T & object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>a : unknown
|
||||
|
||||
x.b;
|
||||
>x.b : unknown
|
||||
>x : T & object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>b : unknown
|
||||
|
||||
x.c;
|
||||
>x.c : unknown
|
||||
>x : T & object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>c : unknown
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
>f4 : (x: { a: string;}) => void
|
||||
>x : { a: string; }
|
||||
>a : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; }
|
||||
|
||||
x.a;
|
||||
>x.a : string
|
||||
>x : { a: string; }
|
||||
>a : string
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
>"a" in x && "b" in x && "c" in x : boolean
|
||||
>"a" in x && "b" in x : boolean
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; }
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : { a: string; }
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : { a: string; } & Record<"b", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : string
|
||||
>x : { a: string; } & Record<"b", unknown> & Record<"c", unknown>
|
||||
>a : string
|
||||
|
||||
x.b;
|
||||
>x.b : unknown
|
||||
>x : { a: string; } & Record<"b", unknown> & Record<"c", unknown>
|
||||
>b : unknown
|
||||
|
||||
x.c;
|
||||
>x.c : unknown
|
||||
>x : { a: string; } & Record<"b", unknown> & Record<"c", unknown>
|
||||
>c : unknown
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
>f5 : (x: { a: string;} | { b: string;}) => void
|
||||
>x : { a: string; } | { b: string; }
|
||||
>a : string
|
||||
>b : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; } | { b: string; }
|
||||
|
||||
x; // { a: string }
|
||||
>x : { a: string; }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : { b: string; }
|
||||
|
||||
x; // { b: string }
|
||||
>x : { b: string; }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : never
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
>f6 : (x: { a: string;} | { b: string;}) => void
|
||||
>x : { a: string; } | { b: string; }
|
||||
>a : string
|
||||
>b : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; } | { b: string; }
|
||||
|
||||
x; // { a: string }
|
||||
>x : { a: string; }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { b: string; }
|
||||
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
>x : { b: string; } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
>x : { b: string; }
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
>f7 : (x: { a: string; b: number;}, y: { a: string;} & { b: number;}) => void
|
||||
>x : { a: string; b: number; }
|
||||
>a : string
|
||||
>b : number
|
||||
>y : { a: string; } & { b: number; }
|
||||
>a : string
|
||||
>b : number
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; b: number; }
|
||||
|
||||
x;
|
||||
>x : { a: string; b: number; }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : never
|
||||
}
|
||||
if ("a" in y) {
|
||||
>"a" in y : boolean
|
||||
>"a" : "a"
|
||||
>y : { a: string; } & { b: number; }
|
||||
|
||||
y;
|
||||
>y : { a: string; } & { b: number; }
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
>y : never
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
>sym : unique symbol
|
||||
>Symbol() : unique symbol
|
||||
>Symbol : SymbolConstructor
|
||||
|
||||
function f8(x: object) {
|
||||
>f8 : (x: object) => void
|
||||
>x : object
|
||||
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
>"a" in x && 1 in x && sym in x : boolean
|
||||
>"a" in x && 1 in x : boolean
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
>1 in x : boolean
|
||||
>1 : 1
|
||||
>x : object & Record<"a", unknown>
|
||||
>sym in x : boolean
|
||||
>sym : unique symbol
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>a : unknown
|
||||
|
||||
x["a"];
|
||||
>x["a"] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>"a" : "a"
|
||||
|
||||
x[1];
|
||||
>x[1] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>1 : 1
|
||||
|
||||
x["1"];
|
||||
>x["1"] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>"1" : "1"
|
||||
|
||||
x[sym];
|
||||
>x[sym] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>sym : unique symbol
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
>f9 : (x: object) => void
|
||||
>x : object
|
||||
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
>"a" in x && "1" in x && sym in x : boolean
|
||||
>"a" in x && "1" in x : boolean
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
>"1" in x : boolean
|
||||
>"1" : "1"
|
||||
>x : object & Record<"a", unknown>
|
||||
>sym in x : boolean
|
||||
>sym : unique symbol
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>a : unknown
|
||||
|
||||
x["a"];
|
||||
>x["a"] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>"a" : "a"
|
||||
|
||||
x[1];
|
||||
>x[1] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>1 : 1
|
||||
|
||||
x["1"];
|
||||
>x["1"] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>"1" : "1"
|
||||
|
||||
x[sym];
|
||||
>x[sym] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>sym : unique symbol
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
>foo : <A>(value: A) => void
|
||||
>value : A
|
||||
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
>typeof value === "object" && value !== null && "prop" in value : boolean
|
||||
>typeof value === "object" && value !== null : boolean
|
||||
>typeof value === "object" : boolean
|
||||
>typeof value : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>value : A
|
||||
>"object" : "object"
|
||||
>value !== null : boolean
|
||||
>value : A & object
|
||||
>null : null
|
||||
>"prop" in value : boolean
|
||||
>"prop" : "prop"
|
||||
>value : A & object
|
||||
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
>value : A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,383 @@
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(1,11): error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(2,11): error TS2564: Property 'b' has no initializer and is not definitely assigned in the constructor.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(6,11): error TS2339: Property 'b' does not exist on type 'A'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(8,11): error TS2339: Property 'a' does not exist on type 'B'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(14,11): error TS2339: Property 'b' does not exist on type 'A'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(16,11): error TS2339: Property 'a' does not exist on type 'B'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(27,11): error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'.
|
||||
Property 'b' does not exist on type 'AWithOptionalProp'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(42,11): error TS2339: Property 'b' does not exist on type 'AWithMethod'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(49,11): error TS2339: Property 'a' does not exist on type '(AWithMethod | BWithMethod) & Record<"c", unknown>'.
|
||||
Property 'a' does not exist on type 'BWithMethod & Record<"c", unknown>'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(50,11): error TS2339: Property 'b' does not exist on type '(AWithMethod | BWithMethod) & Record<"c", unknown>'.
|
||||
Property 'b' does not exist on type 'AWithMethod & Record<"c", unknown>'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(52,11): error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'.
|
||||
Property 'a' does not exist on type 'BWithMethod'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(53,11): error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'.
|
||||
Property 'b' does not exist on type 'AWithMethod'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(57,11): error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(58,11): error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(62,11): error TS2339: Property 'b' does not exist on type 'A | C | D'.
|
||||
Property 'b' does not exist on type 'A'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(64,11): error TS2339: Property 'a' does not exist on type 'B'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(68,28): error TS2564: Property 'prop' has no initializer and is not definitely assigned in the constructor.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(72,32): error TS2339: Property 'b' does not exist on type 'A'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(74,32): error TS2339: Property 'a' does not exist on type 'B'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(79,15): error TS2564: Property 'prop' has no initializer and is not definitely assigned in the constructor.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(82,39): error TS2339: Property 'b' does not exist on type 'A'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(84,39): error TS2339: Property 'a' does not exist on type 'B'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(90,5): error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(94,26): error TS2339: Property 'a' does not exist on type 'never'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(150,16): error TS2339: Property 'ontouchstart' does not exist on type 'never'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(155,16): error TS18046: 'x' is of type 'unknown'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(158,21): error TS2638: Type '{}' may represent a primitive value, which is not permitted as the right operand of the 'in' operator.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(183,16): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
tests/cases/compiler/inKeywordTypeguard.ts(186,21): error TS2638: Type 'NonNullable<T>' may represent a primitive value, which is not permitted as the right operand of the 'in' operator.
|
||||
|
||||
|
||||
==== tests/cases/compiler/inKeywordTypeguard.ts (29 errors) ====
|
||||
class A { a: string; }
|
||||
~
|
||||
!!! error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
class B { b: string; }
|
||||
~
|
||||
!!! error TS2564: Property 'b' has no initializer and is not definitely assigned in the constructor.
|
||||
|
||||
function negativeClassesTest(x: A | B) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'A'.
|
||||
} else {
|
||||
x.a = "1";
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'B'.
|
||||
}
|
||||
}
|
||||
|
||||
function positiveClassesTest(x: A | B) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'A'.
|
||||
} else {
|
||||
x.a = "1";
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'B'.
|
||||
}
|
||||
}
|
||||
|
||||
class AWithOptionalProp { a?: string; }
|
||||
class BWithOptionalProp { b?: string; }
|
||||
|
||||
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
|
||||
if ("a" in x) {
|
||||
x.a = "1";
|
||||
} else {
|
||||
x.b = "1";
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'AWithOptionalProp | BWithOptionalProp'.
|
||||
!!! error TS2339: Property 'b' does not exist on type 'AWithOptionalProp'.
|
||||
}
|
||||
}
|
||||
|
||||
class AWithMethod {
|
||||
a(): string { return ""; }
|
||||
}
|
||||
|
||||
class BWithMethod {
|
||||
b(): string { return ""; }
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
|
||||
if ("a" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod'.
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
|
||||
if ("c" in x) {
|
||||
x.a();
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type '(AWithMethod | BWithMethod) & Record<"c", unknown>'.
|
||||
!!! error TS2339: Property 'a' does not exist on type 'BWithMethod & Record<"c", unknown>'.
|
||||
x.b();
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type '(AWithMethod | BWithMethod) & Record<"c", unknown>'.
|
||||
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod & Record<"c", unknown>'.
|
||||
} else {
|
||||
x.a();
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'AWithMethod | BWithMethod'.
|
||||
!!! error TS2339: Property 'a' does not exist on type 'BWithMethod'.
|
||||
x.b();
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod | BWithMethod'.
|
||||
!!! error TS2339: Property 'b' does not exist on type 'AWithMethod'.
|
||||
}
|
||||
}
|
||||
|
||||
class C { a: string; }
|
||||
~
|
||||
!!! error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
class D { a: string; }
|
||||
~
|
||||
!!! error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
|
||||
function negativeMultipleClassesTest(x: A | B | C | D) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'A | C | D'.
|
||||
!!! error TS2339: Property 'b' does not exist on type 'A'.
|
||||
} else {
|
||||
x.a = "1";
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'B'.
|
||||
}
|
||||
}
|
||||
|
||||
class ClassWithUnionProp { prop: A | B }
|
||||
~~~~
|
||||
!!! error TS2564: Property 'prop' has no initializer and is not definitely assigned in the constructor.
|
||||
|
||||
function negativePropTest(x: ClassWithUnionProp) {
|
||||
if ("a" in x.prop) {
|
||||
let y: string = x.prop.b;
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'A'.
|
||||
} else {
|
||||
let z: string = x.prop.a;
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'B'.
|
||||
}
|
||||
}
|
||||
|
||||
class NegativeClassTest {
|
||||
protected prop: A | B;
|
||||
~~~~
|
||||
!!! error TS2564: Property 'prop' has no initializer and is not definitely assigned in the constructor.
|
||||
inThis() {
|
||||
if ("a" in this.prop) {
|
||||
let z: number = this.prop.b;
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type 'A'.
|
||||
} else {
|
||||
let y: string = this.prop.a;
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'B'.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnreachableCodeDetection {
|
||||
a: string;
|
||||
~
|
||||
!!! error TS2564: Property 'a' has no initializer and is not definitely assigned in the constructor.
|
||||
inThis() {
|
||||
if ("a" in this) {
|
||||
} else {
|
||||
let y = this.a;
|
||||
~
|
||||
!!! error TS2339: Property 'a' does not exist on type 'never'.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positiveIntersectionTest(x: { a: string } & { b: string }) {
|
||||
if ("a" in x) {
|
||||
let s: string = x.a;
|
||||
} else {
|
||||
let n: never = x;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38608
|
||||
declare const error: Error;
|
||||
if ('extra' in error) {
|
||||
error // Still Error
|
||||
} else {
|
||||
error // Error
|
||||
}
|
||||
|
||||
function narrowsToNever(x: { l: number } | { r: number }) {
|
||||
let v: number;
|
||||
if ("l" in x) {
|
||||
v = x.l;
|
||||
}
|
||||
else if ("r" in x) {
|
||||
v = x.r;
|
||||
}
|
||||
else {
|
||||
v = x
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
type AOrB = { aProp: number } | { bProp: number };
|
||||
declare function isAOrB(x: unknown): x is AOrB;
|
||||
|
||||
declare var x: unknown;
|
||||
if (isAOrB(x)) {
|
||||
if ("aProp" in x) {
|
||||
x.aProp;
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
x.bProp;
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
const _never: never = x;
|
||||
}
|
||||
}
|
||||
|
||||
function negativeIntersectionTest() {
|
||||
if ("ontouchstart" in window) {
|
||||
window.ontouchstart
|
||||
} else {
|
||||
window.ontouchstart
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2339: Property 'ontouchstart' does not exist on type 'never'.
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
if ("a" in x) {
|
||||
~
|
||||
!!! error TS18046: 'x' is of type 'unknown'.
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
~
|
||||
!!! error TS2638: Type '{}' may represent a primitive value, which is not permitted as the right operand of the 'in' operator.
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
if ("a" in x) {
|
||||
~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/compiler/inKeywordTypeguard.ts:182:13: This type parameter might need an `extends object` constraint.
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
~
|
||||
!!! error TS2638: Type 'NonNullable<T>' may represent a primitive value, which is not permitted as the right operand of the 'in' operator.
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
x; // { b: string }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
if ("a" in x) {
|
||||
x;
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if ("a" in y) {
|
||||
y;
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
|
||||
function f8(x: object) {
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
|
||||
542
tests/baselines/reference/inKeywordTypeguard(strict=true).js
Normal file
542
tests/baselines/reference/inKeywordTypeguard(strict=true).js
Normal file
@ -0,0 +1,542 @@
|
||||
//// [inKeywordTypeguard.ts]
|
||||
class A { a: string; }
|
||||
class B { b: string; }
|
||||
|
||||
function negativeClassesTest(x: A | B) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
function positiveClassesTest(x: A | B) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class AWithOptionalProp { a?: string; }
|
||||
class BWithOptionalProp { b?: string; }
|
||||
|
||||
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
|
||||
if ("a" in x) {
|
||||
x.a = "1";
|
||||
} else {
|
||||
x.b = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class AWithMethod {
|
||||
a(): string { return ""; }
|
||||
}
|
||||
|
||||
class BWithMethod {
|
||||
b(): string { return ""; }
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
|
||||
if ("a" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
|
||||
if ("c" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
} else {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
}
|
||||
|
||||
class C { a: string; }
|
||||
class D { a: string; }
|
||||
|
||||
function negativeMultipleClassesTest(x: A | B | C | D) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class ClassWithUnionProp { prop: A | B }
|
||||
|
||||
function negativePropTest(x: ClassWithUnionProp) {
|
||||
if ("a" in x.prop) {
|
||||
let y: string = x.prop.b;
|
||||
} else {
|
||||
let z: string = x.prop.a;
|
||||
}
|
||||
}
|
||||
|
||||
class NegativeClassTest {
|
||||
protected prop: A | B;
|
||||
inThis() {
|
||||
if ("a" in this.prop) {
|
||||
let z: number = this.prop.b;
|
||||
} else {
|
||||
let y: string = this.prop.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnreachableCodeDetection {
|
||||
a: string;
|
||||
inThis() {
|
||||
if ("a" in this) {
|
||||
} else {
|
||||
let y = this.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positiveIntersectionTest(x: { a: string } & { b: string }) {
|
||||
if ("a" in x) {
|
||||
let s: string = x.a;
|
||||
} else {
|
||||
let n: never = x;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38608
|
||||
declare const error: Error;
|
||||
if ('extra' in error) {
|
||||
error // Still Error
|
||||
} else {
|
||||
error // Error
|
||||
}
|
||||
|
||||
function narrowsToNever(x: { l: number } | { r: number }) {
|
||||
let v: number;
|
||||
if ("l" in x) {
|
||||
v = x.l;
|
||||
}
|
||||
else if ("r" in x) {
|
||||
v = x.r;
|
||||
}
|
||||
else {
|
||||
v = x
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
type AOrB = { aProp: number } | { bProp: number };
|
||||
declare function isAOrB(x: unknown): x is AOrB;
|
||||
|
||||
declare var x: unknown;
|
||||
if (isAOrB(x)) {
|
||||
if ("aProp" in x) {
|
||||
x.aProp;
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
x.bProp;
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
const _never: never = x;
|
||||
}
|
||||
}
|
||||
|
||||
function negativeIntersectionTest() {
|
||||
if ("ontouchstart" in window) {
|
||||
window.ontouchstart
|
||||
} else {
|
||||
window.ontouchstart
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
x; // { b: string }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
if ("a" in x) {
|
||||
x;
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if ("a" in y) {
|
||||
y;
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
|
||||
function f8(x: object) {
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [inKeywordTypeguard.js]
|
||||
"use strict";
|
||||
class A {
|
||||
}
|
||||
class B {
|
||||
}
|
||||
function negativeClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
function positiveClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
class AWithOptionalProp {
|
||||
}
|
||||
class BWithOptionalProp {
|
||||
}
|
||||
function positiveTestClassesWithOptionalProperties(x) {
|
||||
if ("a" in x) {
|
||||
x.a = "1";
|
||||
}
|
||||
else {
|
||||
x.b = "1";
|
||||
}
|
||||
}
|
||||
class AWithMethod {
|
||||
a() { return ""; }
|
||||
}
|
||||
class BWithMethod {
|
||||
b() { return ""; }
|
||||
}
|
||||
function negativeTestClassesWithMembers(x) {
|
||||
if ("a" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x) {
|
||||
if ("c" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
else {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
}
|
||||
class C {
|
||||
}
|
||||
class D {
|
||||
}
|
||||
function negativeMultipleClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
class ClassWithUnionProp {
|
||||
}
|
||||
function negativePropTest(x) {
|
||||
if ("a" in x.prop) {
|
||||
let y = x.prop.b;
|
||||
}
|
||||
else {
|
||||
let z = x.prop.a;
|
||||
}
|
||||
}
|
||||
class NegativeClassTest {
|
||||
inThis() {
|
||||
if ("a" in this.prop) {
|
||||
let z = this.prop.b;
|
||||
}
|
||||
else {
|
||||
let y = this.prop.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
class UnreachableCodeDetection {
|
||||
inThis() {
|
||||
if ("a" in this) {
|
||||
}
|
||||
else {
|
||||
let y = this.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
function positiveIntersectionTest(x) {
|
||||
if ("a" in x) {
|
||||
let s = x.a;
|
||||
}
|
||||
else {
|
||||
let n = x;
|
||||
}
|
||||
}
|
||||
if ('extra' in error) {
|
||||
error; // Still Error
|
||||
}
|
||||
else {
|
||||
error; // Error
|
||||
}
|
||||
function narrowsToNever(x) {
|
||||
let v;
|
||||
if ("l" in x) {
|
||||
v = x.l;
|
||||
}
|
||||
else if ("r" in x) {
|
||||
v = x.r;
|
||||
}
|
||||
else {
|
||||
v = x;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
if (isAOrB(x)) {
|
||||
if ("aProp" in x) {
|
||||
x.aProp;
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
x.bProp;
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
const _never = x;
|
||||
}
|
||||
}
|
||||
function negativeIntersectionTest() {
|
||||
if ("ontouchstart" in window) {
|
||||
window.ontouchstart;
|
||||
}
|
||||
else {
|
||||
window.ontouchstart;
|
||||
}
|
||||
}
|
||||
function f1(x) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
function f2(x) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
function f3(x) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
function f4(x) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
function f5(x) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
x; // { b: string }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
}
|
||||
function f6(x) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
}
|
||||
}
|
||||
// Object and corresponding intersection should narrow the same
|
||||
function f7(x, y) {
|
||||
if ("a" in x) {
|
||||
x;
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if ("a" in y) {
|
||||
y;
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
}
|
||||
}
|
||||
const sym = Symbol();
|
||||
function f8(x) {
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
function f9(x) {
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
// Repro from #50639
|
||||
function foo(value) {
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,727 @@
|
||||
=== tests/cases/compiler/inKeywordTypeguard.ts ===
|
||||
class A { a: string; }
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
|
||||
>a : Symbol(A.a, Decl(inKeywordTypeguard.ts, 0, 9))
|
||||
|
||||
class B { b: string; }
|
||||
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
|
||||
>b : Symbol(B.b, Decl(inKeywordTypeguard.ts, 1, 9))
|
||||
|
||||
function negativeClassesTest(x: A | B) {
|
||||
>negativeClassesTest : Symbol(negativeClassesTest, Decl(inKeywordTypeguard.ts, 1, 22))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29))
|
||||
|
||||
x.b = "1";
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29))
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 3, 29))
|
||||
}
|
||||
}
|
||||
|
||||
function positiveClassesTest(x: A | B) {
|
||||
>positiveClassesTest : Symbol(positiveClassesTest, Decl(inKeywordTypeguard.ts, 9, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29))
|
||||
|
||||
x.b = "1";
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29))
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 11, 29))
|
||||
}
|
||||
}
|
||||
|
||||
class AWithOptionalProp { a?: string; }
|
||||
>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(inKeywordTypeguard.ts, 17, 1))
|
||||
>a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25))
|
||||
|
||||
class BWithOptionalProp { b?: string; }
|
||||
>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(inKeywordTypeguard.ts, 19, 39))
|
||||
>b : Symbol(BWithOptionalProp.b, Decl(inKeywordTypeguard.ts, 20, 25))
|
||||
|
||||
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
|
||||
>positiveTestClassesWithOptionalProperties : Symbol(positiveTestClassesWithOptionalProperties, Decl(inKeywordTypeguard.ts, 20, 39))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51))
|
||||
>AWithOptionalProp : Symbol(AWithOptionalProp, Decl(inKeywordTypeguard.ts, 17, 1))
|
||||
>BWithOptionalProp : Symbol(BWithOptionalProp, Decl(inKeywordTypeguard.ts, 19, 39))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51))
|
||||
|
||||
x.a = "1";
|
||||
>x.a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51))
|
||||
>a : Symbol(AWithOptionalProp.a, Decl(inKeywordTypeguard.ts, 19, 25))
|
||||
|
||||
} else {
|
||||
x.b = "1";
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 22, 51))
|
||||
}
|
||||
}
|
||||
|
||||
class AWithMethod {
|
||||
>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1))
|
||||
|
||||
a(): string { return ""; }
|
||||
>a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19))
|
||||
}
|
||||
|
||||
class BWithMethod {
|
||||
>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1))
|
||||
|
||||
b(): string { return ""; }
|
||||
>b : Symbol(BWithMethod.b, Decl(inKeywordTypeguard.ts, 34, 19))
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
|
||||
>negativeTestClassesWithMembers : Symbol(negativeTestClassesWithMembers, Decl(inKeywordTypeguard.ts, 36, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40))
|
||||
>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1))
|
||||
>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40))
|
||||
|
||||
x.a();
|
||||
>x.a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40))
|
||||
>a : Symbol(AWithMethod.a, Decl(inKeywordTypeguard.ts, 30, 19))
|
||||
|
||||
x.b();
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 38, 40))
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
|
||||
>negativeTestClassesWithMemberMissingInBothClasses : Symbol(negativeTestClassesWithMemberMissingInBothClasses, Decl(inKeywordTypeguard.ts, 44, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
|
||||
>AWithMethod : Symbol(AWithMethod, Decl(inKeywordTypeguard.ts, 28, 1))
|
||||
>BWithMethod : Symbol(BWithMethod, Decl(inKeywordTypeguard.ts, 32, 1))
|
||||
|
||||
if ("c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
|
||||
|
||||
x.a();
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
|
||||
|
||||
x.b();
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
|
||||
|
||||
} else {
|
||||
x.a();
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
|
||||
|
||||
x.b();
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 46, 59))
|
||||
}
|
||||
}
|
||||
|
||||
class C { a: string; }
|
||||
>C : Symbol(C, Decl(inKeywordTypeguard.ts, 54, 1))
|
||||
>a : Symbol(C.a, Decl(inKeywordTypeguard.ts, 56, 9))
|
||||
|
||||
class D { a: string; }
|
||||
>D : Symbol(D, Decl(inKeywordTypeguard.ts, 56, 22))
|
||||
>a : Symbol(D.a, Decl(inKeywordTypeguard.ts, 57, 9))
|
||||
|
||||
function negativeMultipleClassesTest(x: A | B | C | D) {
|
||||
>negativeMultipleClassesTest : Symbol(negativeMultipleClassesTest, Decl(inKeywordTypeguard.ts, 57, 22))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
|
||||
>C : Symbol(C, Decl(inKeywordTypeguard.ts, 54, 1))
|
||||
>D : Symbol(D, Decl(inKeywordTypeguard.ts, 56, 22))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37))
|
||||
|
||||
x.b = "1";
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37))
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 59, 37))
|
||||
}
|
||||
}
|
||||
|
||||
class ClassWithUnionProp { prop: A | B }
|
||||
>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(inKeywordTypeguard.ts, 65, 1))
|
||||
>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
|
||||
|
||||
function negativePropTest(x: ClassWithUnionProp) {
|
||||
>negativePropTest : Symbol(negativePropTest, Decl(inKeywordTypeguard.ts, 67, 40))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26))
|
||||
>ClassWithUnionProp : Symbol(ClassWithUnionProp, Decl(inKeywordTypeguard.ts, 65, 1))
|
||||
|
||||
if ("a" in x.prop) {
|
||||
>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26))
|
||||
>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
|
||||
|
||||
let y: string = x.prop.b;
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 71, 11))
|
||||
>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26))
|
||||
>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
|
||||
|
||||
} else {
|
||||
let z: string = x.prop.a;
|
||||
>z : Symbol(z, Decl(inKeywordTypeguard.ts, 73, 11))
|
||||
>x.prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 69, 26))
|
||||
>prop : Symbol(ClassWithUnionProp.prop, Decl(inKeywordTypeguard.ts, 67, 26))
|
||||
}
|
||||
}
|
||||
|
||||
class NegativeClassTest {
|
||||
>NegativeClassTest : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1))
|
||||
|
||||
protected prop: A | B;
|
||||
>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 0, 0))
|
||||
>B : Symbol(B, Decl(inKeywordTypeguard.ts, 0, 22))
|
||||
|
||||
inThis() {
|
||||
>inThis : Symbol(NegativeClassTest.inThis, Decl(inKeywordTypeguard.ts, 78, 26))
|
||||
|
||||
if ("a" in this.prop) {
|
||||
>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
|
||||
>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1))
|
||||
>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
|
||||
|
||||
let z: number = this.prop.b;
|
||||
>z : Symbol(z, Decl(inKeywordTypeguard.ts, 81, 15))
|
||||
>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
|
||||
>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1))
|
||||
>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
|
||||
|
||||
} else {
|
||||
let y: string = this.prop.a;
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 83, 15))
|
||||
>this.prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
|
||||
>this : Symbol(NegativeClassTest, Decl(inKeywordTypeguard.ts, 75, 1))
|
||||
>prop : Symbol(NegativeClassTest.prop, Decl(inKeywordTypeguard.ts, 77, 25))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnreachableCodeDetection {
|
||||
>UnreachableCodeDetection : Symbol(UnreachableCodeDetection, Decl(inKeywordTypeguard.ts, 86, 1))
|
||||
|
||||
a: string;
|
||||
>a : Symbol(UnreachableCodeDetection.a, Decl(inKeywordTypeguard.ts, 88, 32))
|
||||
|
||||
inThis() {
|
||||
>inThis : Symbol(UnreachableCodeDetection.inThis, Decl(inKeywordTypeguard.ts, 89, 14))
|
||||
|
||||
if ("a" in this) {
|
||||
>this : Symbol(UnreachableCodeDetection, Decl(inKeywordTypeguard.ts, 86, 1))
|
||||
|
||||
} else {
|
||||
let y = this.a;
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 93, 15))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positiveIntersectionTest(x: { a: string } & { b: string }) {
|
||||
>positiveIntersectionTest : Symbol(positiveIntersectionTest, Decl(inKeywordTypeguard.ts, 96, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 98, 34))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 98, 38))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 98, 54))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 98, 34))
|
||||
|
||||
let s: string = x.a;
|
||||
>s : Symbol(s, Decl(inKeywordTypeguard.ts, 100, 11))
|
||||
>x.a : Symbol(a, Decl(inKeywordTypeguard.ts, 98, 38))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 98, 34))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 98, 38))
|
||||
|
||||
} else {
|
||||
let n: never = x;
|
||||
>n : Symbol(n, Decl(inKeywordTypeguard.ts, 102, 11))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 98, 34))
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38608
|
||||
declare const error: Error;
|
||||
>error : Symbol(error, Decl(inKeywordTypeguard.ts, 107, 13))
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
|
||||
if ('extra' in error) {
|
||||
>error : Symbol(error, Decl(inKeywordTypeguard.ts, 107, 13))
|
||||
|
||||
error // Still Error
|
||||
>error : Symbol(error, Decl(inKeywordTypeguard.ts, 107, 13))
|
||||
|
||||
} else {
|
||||
error // Error
|
||||
>error : Symbol(error, Decl(inKeywordTypeguard.ts, 107, 13))
|
||||
}
|
||||
|
||||
function narrowsToNever(x: { l: number } | { r: number }) {
|
||||
>narrowsToNever : Symbol(narrowsToNever, Decl(inKeywordTypeguard.ts, 112, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
|
||||
>l : Symbol(l, Decl(inKeywordTypeguard.ts, 114, 28))
|
||||
>r : Symbol(r, Decl(inKeywordTypeguard.ts, 114, 44))
|
||||
|
||||
let v: number;
|
||||
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
|
||||
|
||||
if ("l" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
|
||||
|
||||
v = x.l;
|
||||
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
|
||||
>x.l : Symbol(l, Decl(inKeywordTypeguard.ts, 114, 28))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
|
||||
>l : Symbol(l, Decl(inKeywordTypeguard.ts, 114, 28))
|
||||
}
|
||||
else if ("r" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
|
||||
|
||||
v = x.r;
|
||||
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
|
||||
>x.r : Symbol(r, Decl(inKeywordTypeguard.ts, 114, 44))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
|
||||
>r : Symbol(r, Decl(inKeywordTypeguard.ts, 114, 44))
|
||||
}
|
||||
else {
|
||||
v = x
|
||||
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 114, 24))
|
||||
}
|
||||
return v;
|
||||
>v : Symbol(v, Decl(inKeywordTypeguard.ts, 115, 7))
|
||||
}
|
||||
|
||||
type AOrB = { aProp: number } | { bProp: number };
|
||||
>AOrB : Symbol(AOrB, Decl(inKeywordTypeguard.ts, 126, 1))
|
||||
>aProp : Symbol(aProp, Decl(inKeywordTypeguard.ts, 128, 13))
|
||||
>bProp : Symbol(bProp, Decl(inKeywordTypeguard.ts, 128, 33))
|
||||
|
||||
declare function isAOrB(x: unknown): x is AOrB;
|
||||
>isAOrB : Symbol(isAOrB, Decl(inKeywordTypeguard.ts, 128, 50))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 129, 24))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 129, 24))
|
||||
>AOrB : Symbol(AOrB, Decl(inKeywordTypeguard.ts, 126, 1))
|
||||
|
||||
declare var x: unknown;
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
|
||||
|
||||
if (isAOrB(x)) {
|
||||
>isAOrB : Symbol(isAOrB, Decl(inKeywordTypeguard.ts, 128, 50))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
|
||||
|
||||
if ("aProp" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
|
||||
|
||||
x.aProp;
|
||||
>x.aProp : Symbol(aProp, Decl(inKeywordTypeguard.ts, 128, 13))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
|
||||
>aProp : Symbol(aProp, Decl(inKeywordTypeguard.ts, 128, 13))
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
|
||||
|
||||
x.bProp;
|
||||
>x.bProp : Symbol(bProp, Decl(inKeywordTypeguard.ts, 128, 33))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
|
||||
>bProp : Symbol(bProp, Decl(inKeywordTypeguard.ts, 128, 33))
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
|
||||
|
||||
const _never: never = x;
|
||||
>_never : Symbol(_never, Decl(inKeywordTypeguard.ts, 141, 13))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 131, 11))
|
||||
}
|
||||
}
|
||||
|
||||
function negativeIntersectionTest() {
|
||||
>negativeIntersectionTest : Symbol(negativeIntersectionTest, Decl(inKeywordTypeguard.ts, 143, 1))
|
||||
|
||||
if ("ontouchstart" in window) {
|
||||
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||
|
||||
window.ontouchstart
|
||||
>window.ontouchstart : Symbol(ontouchstart, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||
>ontouchstart : Symbol(ontouchstart, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
|
||||
|
||||
} else {
|
||||
window.ontouchstart
|
||||
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
>f1 : Symbol(f1, Decl(inKeywordTypeguard.ts, 151, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>a : Symbol(a)
|
||||
|
||||
x.b;
|
||||
>x.b : Symbol(b)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>b : Symbol(b)
|
||||
|
||||
x.c;
|
||||
>x.c : Symbol(c)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 153, 12))
|
||||
>c : Symbol(c)
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
>f2 : Symbol(f2, Decl(inKeywordTypeguard.ts, 168, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>a : Symbol(a)
|
||||
|
||||
x.b;
|
||||
>x.b : Symbol(b)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>b : Symbol(b)
|
||||
|
||||
x.c;
|
||||
>x.c : Symbol(c)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 170, 12))
|
||||
>c : Symbol(c)
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
>f3 : Symbol(f3, Decl(inKeywordTypeguard.ts, 179, 1))
|
||||
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 181, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 181, 12))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>a : Symbol(a)
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>a : Symbol(a)
|
||||
|
||||
x.b;
|
||||
>x.b : Symbol(b)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>b : Symbol(b)
|
||||
|
||||
x.c;
|
||||
>x.c : Symbol(c)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 181, 15))
|
||||
>c : Symbol(c)
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
>f4 : Symbol(f4, Decl(inKeywordTypeguard.ts, 196, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 198, 16))
|
||||
|
||||
x.b;
|
||||
>x.b : Symbol(b)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>b : Symbol(b)
|
||||
|
||||
x.c;
|
||||
>x.c : Symbol(c)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 198, 12))
|
||||
>c : Symbol(c)
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
>f5 : Symbol(f5, Decl(inKeywordTypeguard.ts, 207, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 209, 16))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 209, 32))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
|
||||
x; // { a: string }
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
}
|
||||
else if ("b" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
|
||||
x; // { b: string }
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 209, 12))
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
>f6 : Symbol(f6, Decl(inKeywordTypeguard.ts, 219, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 221, 16))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 221, 32))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
|
||||
x; // { a: string }
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
}
|
||||
else if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 221, 12))
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
>f7 : Symbol(f7, Decl(inKeywordTypeguard.ts, 231, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 235, 12))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 235, 16))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 235, 27))
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 235, 40))
|
||||
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 235, 45))
|
||||
>b : Symbol(b, Decl(inKeywordTypeguard.ts, 235, 61))
|
||||
|
||||
if ("a" in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 235, 12))
|
||||
|
||||
x;
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 235, 12))
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 235, 12))
|
||||
}
|
||||
if ("a" in y) {
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 235, 40))
|
||||
|
||||
y;
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 235, 40))
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
>y : Symbol(y, Decl(inKeywordTypeguard.ts, 235, 40))
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
|
||||
|
||||
function f8(x: object) {
|
||||
>f8 : Symbol(f8, Decl(inKeywordTypeguard.ts, 250, 21))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>a : Symbol(a)
|
||||
|
||||
x["a"];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>"a" : Symbol(a)
|
||||
|
||||
x[1];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>1 : Symbol(1)
|
||||
|
||||
x["1"];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>"1" : Symbol(1)
|
||||
|
||||
x[sym];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 252, 12))
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
>f9 : Symbol(f9, Decl(inKeywordTypeguard.ts, 260, 1))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
|
||||
x.a;
|
||||
>x.a : Symbol(a)
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>a : Symbol(a)
|
||||
|
||||
x["a"];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>"a" : Symbol(a)
|
||||
|
||||
x[1];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>1 : Symbol(1)
|
||||
|
||||
x["1"];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>"1" : Symbol(1)
|
||||
|
||||
x[sym];
|
||||
>x : Symbol(x, Decl(inKeywordTypeguard.ts, 262, 12))
|
||||
>sym : Symbol(sym, Decl(inKeywordTypeguard.ts, 250, 5))
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
>foo : Symbol(foo, Decl(inKeywordTypeguard.ts, 270, 1))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 274, 13))
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
>A : Symbol(A, Decl(inKeywordTypeguard.ts, 274, 13))
|
||||
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
>value : Symbol(value, Decl(inKeywordTypeguard.ts, 274, 16))
|
||||
}
|
||||
}
|
||||
|
||||
914
tests/baselines/reference/inKeywordTypeguard(strict=true).types
Normal file
914
tests/baselines/reference/inKeywordTypeguard(strict=true).types
Normal file
@ -0,0 +1,914 @@
|
||||
=== tests/cases/compiler/inKeywordTypeguard.ts ===
|
||||
class A { a: string; }
|
||||
>A : A
|
||||
>a : string
|
||||
|
||||
class B { b: string; }
|
||||
>B : B
|
||||
>b : string
|
||||
|
||||
function negativeClassesTest(x: A | B) {
|
||||
>negativeClassesTest : (x: A | B) => void
|
||||
>x : A | B
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
function positiveClassesTest(x: A | B) {
|
||||
>positiveClassesTest : (x: A | B) => void
|
||||
>x : A | B
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class AWithOptionalProp { a?: string; }
|
||||
>AWithOptionalProp : AWithOptionalProp
|
||||
>a : string | undefined
|
||||
|
||||
class BWithOptionalProp { b?: string; }
|
||||
>BWithOptionalProp : BWithOptionalProp
|
||||
>b : string | undefined
|
||||
|
||||
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
|
||||
>positiveTestClassesWithOptionalProperties : (x: AWithOptionalProp | BWithOptionalProp) => void
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : string | undefined
|
||||
>x : AWithOptionalProp
|
||||
>a : string | undefined
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class AWithMethod {
|
||||
>AWithMethod : AWithMethod
|
||||
|
||||
a(): string { return ""; }
|
||||
>a : () => string
|
||||
>"" : ""
|
||||
}
|
||||
|
||||
class BWithMethod {
|
||||
>BWithMethod : BWithMethod
|
||||
|
||||
b(): string { return ""; }
|
||||
>b : () => string
|
||||
>"" : ""
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
|
||||
>negativeTestClassesWithMembers : (x: AWithMethod | BWithMethod) => void
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
x.a();
|
||||
>x.a() : string
|
||||
>x.a : () => string
|
||||
>x : AWithMethod
|
||||
>a : () => string
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : AWithMethod
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
|
||||
>negativeTestClassesWithMemberMissingInBothClasses : (x: AWithMethod | BWithMethod) => void
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
if ("c" in x) {
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
x.a();
|
||||
>x.a() : any
|
||||
>x.a : any
|
||||
>x : (AWithMethod | BWithMethod) & Record<"c", unknown>
|
||||
>a : any
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : (AWithMethod | BWithMethod) & Record<"c", unknown>
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
x.a();
|
||||
>x.a() : any
|
||||
>x.a : any
|
||||
>x : AWithMethod | BWithMethod
|
||||
>a : any
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : AWithMethod | BWithMethod
|
||||
>b : any
|
||||
}
|
||||
}
|
||||
|
||||
class C { a: string; }
|
||||
>C : C
|
||||
>a : string
|
||||
|
||||
class D { a: string; }
|
||||
>D : D
|
||||
>a : string
|
||||
|
||||
function negativeMultipleClassesTest(x: A | B | C | D) {
|
||||
>negativeMultipleClassesTest : (x: A | B | C | D) => void
|
||||
>x : A | B | C | D
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B | C | D
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A | C | D
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class ClassWithUnionProp { prop: A | B }
|
||||
>ClassWithUnionProp : ClassWithUnionProp
|
||||
>prop : A | B
|
||||
|
||||
function negativePropTest(x: ClassWithUnionProp) {
|
||||
>negativePropTest : (x: ClassWithUnionProp) => void
|
||||
>x : ClassWithUnionProp
|
||||
|
||||
if ("a" in x.prop) {
|
||||
>"a" in x.prop : boolean
|
||||
>"a" : "a"
|
||||
>x.prop : A | B
|
||||
>x : ClassWithUnionProp
|
||||
>prop : A | B
|
||||
|
||||
let y: string = x.prop.b;
|
||||
>y : string
|
||||
>x.prop.b : any
|
||||
>x.prop : A
|
||||
>x : ClassWithUnionProp
|
||||
>prop : A
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
let z: string = x.prop.a;
|
||||
>z : string
|
||||
>x.prop.a : any
|
||||
>x.prop : B
|
||||
>x : ClassWithUnionProp
|
||||
>prop : B
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
|
||||
class NegativeClassTest {
|
||||
>NegativeClassTest : NegativeClassTest
|
||||
|
||||
protected prop: A | B;
|
||||
>prop : A | B
|
||||
|
||||
inThis() {
|
||||
>inThis : () => void
|
||||
|
||||
if ("a" in this.prop) {
|
||||
>"a" in this.prop : boolean
|
||||
>"a" : "a"
|
||||
>this.prop : A | B
|
||||
>this : this
|
||||
>prop : A | B
|
||||
|
||||
let z: number = this.prop.b;
|
||||
>z : number
|
||||
>this.prop.b : any
|
||||
>this.prop : A
|
||||
>this : this
|
||||
>prop : A
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
let y: string = this.prop.a;
|
||||
>y : string
|
||||
>this.prop.a : any
|
||||
>this.prop : B
|
||||
>this : this
|
||||
>prop : B
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnreachableCodeDetection {
|
||||
>UnreachableCodeDetection : UnreachableCodeDetection
|
||||
|
||||
a: string;
|
||||
>a : string
|
||||
|
||||
inThis() {
|
||||
>inThis : () => void
|
||||
|
||||
if ("a" in this) {
|
||||
>"a" in this : boolean
|
||||
>"a" : "a"
|
||||
>this : this
|
||||
|
||||
} else {
|
||||
let y = this.a;
|
||||
>y : any
|
||||
>this.a : any
|
||||
>this : never
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positiveIntersectionTest(x: { a: string } & { b: string }) {
|
||||
>positiveIntersectionTest : (x: { a: string;} & { b: string;}) => void
|
||||
>x : { a: string; } & { b: string; }
|
||||
>a : string
|
||||
>b : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; } & { b: string; }
|
||||
|
||||
let s: string = x.a;
|
||||
>s : string
|
||||
>x.a : string
|
||||
>x : { a: string; } & { b: string; }
|
||||
>a : string
|
||||
|
||||
} else {
|
||||
let n: never = x;
|
||||
>n : never
|
||||
>x : never
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38608
|
||||
declare const error: Error;
|
||||
>error : Error
|
||||
|
||||
if ('extra' in error) {
|
||||
>'extra' in error : boolean
|
||||
>'extra' : "extra"
|
||||
>error : Error
|
||||
|
||||
error // Still Error
|
||||
>error : Error & Record<"extra", unknown>
|
||||
|
||||
} else {
|
||||
error // Error
|
||||
>error : Error
|
||||
}
|
||||
|
||||
function narrowsToNever(x: { l: number } | { r: number }) {
|
||||
>narrowsToNever : (x: { l: number;} | { r: number;}) => number
|
||||
>x : { l: number; } | { r: number; }
|
||||
>l : number
|
||||
>r : number
|
||||
|
||||
let v: number;
|
||||
>v : number
|
||||
|
||||
if ("l" in x) {
|
||||
>"l" in x : boolean
|
||||
>"l" : "l"
|
||||
>x : { l: number; } | { r: number; }
|
||||
|
||||
v = x.l;
|
||||
>v = x.l : number
|
||||
>v : number
|
||||
>x.l : number
|
||||
>x : { l: number; }
|
||||
>l : number
|
||||
}
|
||||
else if ("r" in x) {
|
||||
>"r" in x : boolean
|
||||
>"r" : "r"
|
||||
>x : { r: number; }
|
||||
|
||||
v = x.r;
|
||||
>v = x.r : number
|
||||
>v : number
|
||||
>x.r : number
|
||||
>x : { r: number; }
|
||||
>r : number
|
||||
}
|
||||
else {
|
||||
v = x
|
||||
>v = x : never
|
||||
>v : number
|
||||
>x : never
|
||||
}
|
||||
return v;
|
||||
>v : number
|
||||
}
|
||||
|
||||
type AOrB = { aProp: number } | { bProp: number };
|
||||
>AOrB : { aProp: number; } | { bProp: number; }
|
||||
>aProp : number
|
||||
>bProp : number
|
||||
|
||||
declare function isAOrB(x: unknown): x is AOrB;
|
||||
>isAOrB : (x: unknown) => x is AOrB
|
||||
>x : unknown
|
||||
|
||||
declare var x: unknown;
|
||||
>x : unknown
|
||||
|
||||
if (isAOrB(x)) {
|
||||
>isAOrB(x) : boolean
|
||||
>isAOrB : (x: unknown) => x is AOrB
|
||||
>x : unknown
|
||||
|
||||
if ("aProp" in x) {
|
||||
>"aProp" in x : boolean
|
||||
>"aProp" : "aProp"
|
||||
>x : AOrB
|
||||
|
||||
x.aProp;
|
||||
>x.aProp : number
|
||||
>x : { aProp: number; }
|
||||
>aProp : number
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
>"bProp" in x : boolean
|
||||
>"bProp" : "bProp"
|
||||
>x : { bProp: number; }
|
||||
|
||||
x.bProp;
|
||||
>x.bProp : number
|
||||
>x : { bProp: number; }
|
||||
>bProp : number
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
>"cProp" in x : boolean
|
||||
>"cProp" : "cProp"
|
||||
>x : never
|
||||
|
||||
const _never: never = x;
|
||||
>_never : never
|
||||
>x : never
|
||||
}
|
||||
}
|
||||
|
||||
function negativeIntersectionTest() {
|
||||
>negativeIntersectionTest : () => void
|
||||
|
||||
if ("ontouchstart" in window) {
|
||||
>"ontouchstart" in window : boolean
|
||||
>"ontouchstart" : "ontouchstart"
|
||||
>window : Window & typeof globalThis
|
||||
|
||||
window.ontouchstart
|
||||
>window.ontouchstart : (((this: GlobalEventHandlers, ev: TouchEvent) => any) & ((this: Window, ev: TouchEvent) => any)) | null | undefined
|
||||
>window : Window & typeof globalThis
|
||||
>ontouchstart : (((this: GlobalEventHandlers, ev: TouchEvent) => any) & ((this: Window, ev: TouchEvent) => any)) | null | undefined
|
||||
|
||||
} else {
|
||||
window.ontouchstart
|
||||
>window.ontouchstart : any
|
||||
>window : never
|
||||
>ontouchstart : any
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
>f1 : (x: unknown) => void
|
||||
>x : unknown
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : unknown
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
>x && "a" in x : unknown
|
||||
>x : unknown
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : {}
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
>x && typeof x === "object" && "a" in x : unknown
|
||||
>x && typeof x === "object" : unknown
|
||||
>x : unknown
|
||||
>typeof x === "object" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : {}
|
||||
>"object" : "object"
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
>x && typeof x === "object" && "a" in x && "b" in x && "c" in x : unknown
|
||||
>x && typeof x === "object" && "a" in x && "b" in x : unknown
|
||||
>x && typeof x === "object" && "a" in x : unknown
|
||||
>x && typeof x === "object" : unknown
|
||||
>x : unknown
|
||||
>typeof x === "object" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : {}
|
||||
>"object" : "object"
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : object & Record<"a", unknown>
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>a : unknown
|
||||
|
||||
x.b;
|
||||
>x.b : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>b : unknown
|
||||
|
||||
x.c;
|
||||
>x.c : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>c : unknown
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
>f2 : (x: object) => void
|
||||
>x : object
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
>"a" in x && "b" in x && "c" in x : boolean
|
||||
>"a" in x && "b" in x : boolean
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : object & Record<"a", unknown>
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>a : unknown
|
||||
|
||||
x.b;
|
||||
>x.b : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>b : unknown
|
||||
|
||||
x.c;
|
||||
>x.c : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>c : unknown
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
>f3 : <T>(x: T) => void
|
||||
>x : T
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : T
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : T & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
>x && "a" in x : boolean
|
||||
>x : T
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : NonNullable<T>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : T & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
>x && typeof x === "object" && "a" in x : boolean
|
||||
>x && typeof x === "object" : boolean
|
||||
>x : T
|
||||
>typeof x === "object" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : NonNullable<T>
|
||||
>"object" : "object"
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : T & object
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : T & object & Record<"a", unknown>
|
||||
>a : unknown
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
>x && typeof x === "object" && "a" in x && "b" in x && "c" in x : boolean
|
||||
>x && typeof x === "object" && "a" in x && "b" in x : boolean
|
||||
>x && typeof x === "object" && "a" in x : boolean
|
||||
>x && typeof x === "object" : boolean
|
||||
>x : T
|
||||
>typeof x === "object" : boolean
|
||||
>typeof x : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>x : NonNullable<T>
|
||||
>"object" : "object"
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : T & object
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : T & object & Record<"a", unknown>
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : T & object & Record<"a", unknown> & Record<"b", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : T & object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>a : unknown
|
||||
|
||||
x.b;
|
||||
>x.b : unknown
|
||||
>x : T & object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>b : unknown
|
||||
|
||||
x.c;
|
||||
>x.c : unknown
|
||||
>x : T & object & Record<"a", unknown> & Record<"b", unknown> & Record<"c", unknown>
|
||||
>c : unknown
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
>f4 : (x: { a: string;}) => void
|
||||
>x : { a: string; }
|
||||
>a : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; }
|
||||
|
||||
x.a;
|
||||
>x.a : string
|
||||
>x : { a: string; }
|
||||
>a : string
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
>"a" in x && "b" in x && "c" in x : boolean
|
||||
>"a" in x && "b" in x : boolean
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; }
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : { a: string; }
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : { a: string; } & Record<"b", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : string
|
||||
>x : { a: string; } & Record<"b", unknown> & Record<"c", unknown>
|
||||
>a : string
|
||||
|
||||
x.b;
|
||||
>x.b : unknown
|
||||
>x : { a: string; } & Record<"b", unknown> & Record<"c", unknown>
|
||||
>b : unknown
|
||||
|
||||
x.c;
|
||||
>x.c : unknown
|
||||
>x : { a: string; } & Record<"b", unknown> & Record<"c", unknown>
|
||||
>c : unknown
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
>f5 : (x: { a: string;} | { b: string;}) => void
|
||||
>x : { a: string; } | { b: string; }
|
||||
>a : string
|
||||
>b : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; } | { b: string; }
|
||||
|
||||
x; // { a: string }
|
||||
>x : { a: string; }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
>"b" in x : boolean
|
||||
>"b" : "b"
|
||||
>x : { b: string; }
|
||||
|
||||
x; // { b: string }
|
||||
>x : { b: string; }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : never
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
>f6 : (x: { a: string;} | { b: string;}) => void
|
||||
>x : { a: string; } | { b: string; }
|
||||
>a : string
|
||||
>b : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; } | { b: string; }
|
||||
|
||||
x; // { a: string }
|
||||
>x : { a: string; }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { b: string; }
|
||||
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
>x : { b: string; } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
>x : { b: string; }
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
>f7 : (x: { a: string; b: number;}, y: { a: string;} & { b: number;}) => void
|
||||
>x : { a: string; b: number; }
|
||||
>a : string
|
||||
>b : number
|
||||
>y : { a: string; } & { b: number; }
|
||||
>a : string
|
||||
>b : number
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; b: number; }
|
||||
|
||||
x;
|
||||
>x : { a: string; b: number; }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
>x : never
|
||||
}
|
||||
if ("a" in y) {
|
||||
>"a" in y : boolean
|
||||
>"a" : "a"
|
||||
>y : { a: string; } & { b: number; }
|
||||
|
||||
y;
|
||||
>y : { a: string; } & { b: number; }
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
>y : never
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
>sym : unique symbol
|
||||
>Symbol() : unique symbol
|
||||
>Symbol : SymbolConstructor
|
||||
|
||||
function f8(x: object) {
|
||||
>f8 : (x: object) => void
|
||||
>x : object
|
||||
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
>"a" in x && 1 in x && sym in x : boolean
|
||||
>"a" in x && 1 in x : boolean
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
>1 in x : boolean
|
||||
>1 : 1
|
||||
>x : object & Record<"a", unknown>
|
||||
>sym in x : boolean
|
||||
>sym : unique symbol
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>a : unknown
|
||||
|
||||
x["a"];
|
||||
>x["a"] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>"a" : "a"
|
||||
|
||||
x[1];
|
||||
>x[1] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>1 : 1
|
||||
|
||||
x["1"];
|
||||
>x["1"] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>"1" : "1"
|
||||
|
||||
x[sym];
|
||||
>x[sym] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<1, unknown> & Record<unique symbol, unknown>
|
||||
>sym : unique symbol
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
>f9 : (x: object) => void
|
||||
>x : object
|
||||
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
>"a" in x && "1" in x && sym in x : boolean
|
||||
>"a" in x && "1" in x : boolean
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : object
|
||||
>"1" in x : boolean
|
||||
>"1" : "1"
|
||||
>x : object & Record<"a", unknown>
|
||||
>sym in x : boolean
|
||||
>sym : unique symbol
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown>
|
||||
|
||||
x.a;
|
||||
>x.a : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>a : unknown
|
||||
|
||||
x["a"];
|
||||
>x["a"] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>"a" : "a"
|
||||
|
||||
x[1];
|
||||
>x[1] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>1 : 1
|
||||
|
||||
x["1"];
|
||||
>x["1"] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>"1" : "1"
|
||||
|
||||
x[sym];
|
||||
>x[sym] : unknown
|
||||
>x : object & Record<"a", unknown> & Record<"1", unknown> & Record<unique symbol, unknown>
|
||||
>sym : unique symbol
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
>foo : <A>(value: A) => void
|
||||
>value : A
|
||||
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
>typeof value === "object" && value !== null && "prop" in value : boolean
|
||||
>typeof value === "object" && value !== null : boolean
|
||||
>typeof value === "object" : boolean
|
||||
>typeof value : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
|
||||
>value : A
|
||||
>"object" : "object"
|
||||
>value !== null : boolean
|
||||
>value : (A & object) | (A & null)
|
||||
>null : null
|
||||
>"prop" in value : boolean
|
||||
>"prop" : "prop"
|
||||
>value : A & object
|
||||
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
>value : A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,333 +0,0 @@
|
||||
//// [inKeywordTypeguard.ts]
|
||||
class A { a: string; }
|
||||
class B { b: string; }
|
||||
|
||||
function negativeClassesTest(x: A | B) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
function positiveClassesTest(x: A | B) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class AWithOptionalProp { a?: string; }
|
||||
class BWithOptionalProp { b?: string; }
|
||||
|
||||
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
|
||||
if ("a" in x) {
|
||||
x.a = "1";
|
||||
} else {
|
||||
x.b = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class AWithMethod {
|
||||
a(): string { return ""; }
|
||||
}
|
||||
|
||||
class BWithMethod {
|
||||
b(): string { return ""; }
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
|
||||
if ("a" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
|
||||
if ("c" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
} else {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
}
|
||||
|
||||
class C { a: string; }
|
||||
class D { a: string; }
|
||||
|
||||
function negativeMultipleClassesTest(x: A | B | C | D) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
} else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
|
||||
class ClassWithUnionProp { prop: A | B }
|
||||
|
||||
function negativePropTest(x: ClassWithUnionProp) {
|
||||
if ("a" in x.prop) {
|
||||
let y: string = x.prop.b;
|
||||
} else {
|
||||
let z: string = x.prop.a;
|
||||
}
|
||||
}
|
||||
|
||||
class NegativeClassTest {
|
||||
protected prop: A | B;
|
||||
inThis() {
|
||||
if ("a" in this.prop) {
|
||||
let z: number = this.prop.b;
|
||||
} else {
|
||||
let y: string = this.prop.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnreachableCodeDetection {
|
||||
a: string;
|
||||
inThis() {
|
||||
if ("a" in this) {
|
||||
} else {
|
||||
let y = this.a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positiveIntersectionTest(x: { a: string } & { b: string }) {
|
||||
if ("a" in x) {
|
||||
let s: string = x.a;
|
||||
} else {
|
||||
let n: never = x;
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38608
|
||||
declare const error: Error;
|
||||
if ('extra' in error) {
|
||||
error // Still Error
|
||||
} else {
|
||||
error // Error
|
||||
}
|
||||
|
||||
function narrowsToNever(x: { l: number } | { r: number }) {
|
||||
let v: number;
|
||||
if ("l" in x) {
|
||||
v = x.l;
|
||||
}
|
||||
else if ("r" in x) {
|
||||
v = x.r;
|
||||
}
|
||||
else {
|
||||
v = x
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
type AOrB = { aProp: number } | { bProp: number };
|
||||
declare function isAOrB(x: unknown): x is AOrB;
|
||||
|
||||
declare var x: unknown;
|
||||
if (isAOrB(x)) {
|
||||
if ("aProp" in x) {
|
||||
x.aProp;
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
x.bProp;
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
const _never: never = x;
|
||||
}
|
||||
}
|
||||
|
||||
function negativeIntersectionTest() {
|
||||
if ("ontouchstart" in window) {
|
||||
window.ontouchstart
|
||||
} else {
|
||||
window.ontouchstart
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [inKeywordTypeguard.js]
|
||||
var A = /** @class */ (function () {
|
||||
function A() {
|
||||
}
|
||||
return A;
|
||||
}());
|
||||
var B = /** @class */ (function () {
|
||||
function B() {
|
||||
}
|
||||
return B;
|
||||
}());
|
||||
function negativeClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
function positiveClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
var AWithOptionalProp = /** @class */ (function () {
|
||||
function AWithOptionalProp() {
|
||||
}
|
||||
return AWithOptionalProp;
|
||||
}());
|
||||
var BWithOptionalProp = /** @class */ (function () {
|
||||
function BWithOptionalProp() {
|
||||
}
|
||||
return BWithOptionalProp;
|
||||
}());
|
||||
function positiveTestClassesWithOptionalProperties(x) {
|
||||
if ("a" in x) {
|
||||
x.a = "1";
|
||||
}
|
||||
else {
|
||||
x.b = "1";
|
||||
}
|
||||
}
|
||||
var AWithMethod = /** @class */ (function () {
|
||||
function AWithMethod() {
|
||||
}
|
||||
AWithMethod.prototype.a = function () { return ""; };
|
||||
return AWithMethod;
|
||||
}());
|
||||
var BWithMethod = /** @class */ (function () {
|
||||
function BWithMethod() {
|
||||
}
|
||||
BWithMethod.prototype.b = function () { return ""; };
|
||||
return BWithMethod;
|
||||
}());
|
||||
function negativeTestClassesWithMembers(x) {
|
||||
if ("a" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
else {
|
||||
}
|
||||
}
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x) {
|
||||
if ("c" in x) {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
else {
|
||||
x.a();
|
||||
x.b();
|
||||
}
|
||||
}
|
||||
var C = /** @class */ (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
}());
|
||||
var D = /** @class */ (function () {
|
||||
function D() {
|
||||
}
|
||||
return D;
|
||||
}());
|
||||
function negativeMultipleClassesTest(x) {
|
||||
if ("a" in x) {
|
||||
x.b = "1";
|
||||
}
|
||||
else {
|
||||
x.a = "1";
|
||||
}
|
||||
}
|
||||
var ClassWithUnionProp = /** @class */ (function () {
|
||||
function ClassWithUnionProp() {
|
||||
}
|
||||
return ClassWithUnionProp;
|
||||
}());
|
||||
function negativePropTest(x) {
|
||||
if ("a" in x.prop) {
|
||||
var y = x.prop.b;
|
||||
}
|
||||
else {
|
||||
var z = x.prop.a;
|
||||
}
|
||||
}
|
||||
var NegativeClassTest = /** @class */ (function () {
|
||||
function NegativeClassTest() {
|
||||
}
|
||||
NegativeClassTest.prototype.inThis = function () {
|
||||
if ("a" in this.prop) {
|
||||
var z = this.prop.b;
|
||||
}
|
||||
else {
|
||||
var y = this.prop.a;
|
||||
}
|
||||
};
|
||||
return NegativeClassTest;
|
||||
}());
|
||||
var UnreachableCodeDetection = /** @class */ (function () {
|
||||
function UnreachableCodeDetection() {
|
||||
}
|
||||
UnreachableCodeDetection.prototype.inThis = function () {
|
||||
if ("a" in this) {
|
||||
}
|
||||
else {
|
||||
var y = this.a;
|
||||
}
|
||||
};
|
||||
return UnreachableCodeDetection;
|
||||
}());
|
||||
function positiveIntersectionTest(x) {
|
||||
if ("a" in x) {
|
||||
var s = x.a;
|
||||
}
|
||||
else {
|
||||
var n = x;
|
||||
}
|
||||
}
|
||||
if ('extra' in error) {
|
||||
error; // Still Error
|
||||
}
|
||||
else {
|
||||
error; // Error
|
||||
}
|
||||
function narrowsToNever(x) {
|
||||
var v;
|
||||
if ("l" in x) {
|
||||
v = x.l;
|
||||
}
|
||||
else if ("r" in x) {
|
||||
v = x.r;
|
||||
}
|
||||
else {
|
||||
v = x;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
if (isAOrB(x)) {
|
||||
if ("aProp" in x) {
|
||||
x.aProp;
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
x.bProp;
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
var _never = x;
|
||||
}
|
||||
}
|
||||
function negativeIntersectionTest() {
|
||||
if ("ontouchstart" in window) {
|
||||
window.ontouchstart;
|
||||
}
|
||||
else {
|
||||
window.ontouchstart;
|
||||
}
|
||||
}
|
||||
@ -1,454 +0,0 @@
|
||||
=== tests/cases/compiler/inKeywordTypeguard.ts ===
|
||||
class A { a: string; }
|
||||
>A : A
|
||||
>a : string
|
||||
|
||||
class B { b: string; }
|
||||
>B : B
|
||||
>b : string
|
||||
|
||||
function negativeClassesTest(x: A | B) {
|
||||
>negativeClassesTest : (x: A | B) => void
|
||||
>x : A | B
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
function positiveClassesTest(x: A | B) {
|
||||
>positiveClassesTest : (x: A | B) => void
|
||||
>x : A | B
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class AWithOptionalProp { a?: string; }
|
||||
>AWithOptionalProp : AWithOptionalProp
|
||||
>a : string
|
||||
|
||||
class BWithOptionalProp { b?: string; }
|
||||
>BWithOptionalProp : BWithOptionalProp
|
||||
>b : string
|
||||
|
||||
function positiveTestClassesWithOptionalProperties(x: AWithOptionalProp | BWithOptionalProp) {
|
||||
>positiveTestClassesWithOptionalProperties : (x: AWithOptionalProp | BWithOptionalProp) => void
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : string
|
||||
>x : AWithOptionalProp
|
||||
>a : string
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : AWithOptionalProp | BWithOptionalProp
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class AWithMethod {
|
||||
>AWithMethod : AWithMethod
|
||||
|
||||
a(): string { return ""; }
|
||||
>a : () => string
|
||||
>"" : ""
|
||||
}
|
||||
|
||||
class BWithMethod {
|
||||
>BWithMethod : BWithMethod
|
||||
|
||||
b(): string { return ""; }
|
||||
>b : () => string
|
||||
>"" : ""
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMembers(x: AWithMethod | BWithMethod) {
|
||||
>negativeTestClassesWithMembers : (x: AWithMethod | BWithMethod) => void
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
x.a();
|
||||
>x.a() : string
|
||||
>x.a : () => string
|
||||
>x : AWithMethod
|
||||
>a : () => string
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : AWithMethod
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
}
|
||||
}
|
||||
|
||||
function negativeTestClassesWithMemberMissingInBothClasses(x: AWithMethod | BWithMethod) {
|
||||
>negativeTestClassesWithMemberMissingInBothClasses : (x: AWithMethod | BWithMethod) => void
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
if ("c" in x) {
|
||||
>"c" in x : boolean
|
||||
>"c" : "c"
|
||||
>x : AWithMethod | BWithMethod
|
||||
|
||||
x.a();
|
||||
>x.a() : any
|
||||
>x.a : any
|
||||
>x : never
|
||||
>a : any
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : never
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
x.a();
|
||||
>x.a() : any
|
||||
>x.a : any
|
||||
>x : AWithMethod | BWithMethod
|
||||
>a : any
|
||||
|
||||
x.b();
|
||||
>x.b() : any
|
||||
>x.b : any
|
||||
>x : AWithMethod | BWithMethod
|
||||
>b : any
|
||||
}
|
||||
}
|
||||
|
||||
class C { a: string; }
|
||||
>C : C
|
||||
>a : string
|
||||
|
||||
class D { a: string; }
|
||||
>D : D
|
||||
>a : string
|
||||
|
||||
function negativeMultipleClassesTest(x: A | B | C | D) {
|
||||
>negativeMultipleClassesTest : (x: A | B | C | D) => void
|
||||
>x : A | B | C | D
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : A | B | C | D
|
||||
|
||||
x.b = "1";
|
||||
>x.b = "1" : "1"
|
||||
>x.b : any
|
||||
>x : A | C | D
|
||||
>b : any
|
||||
>"1" : "1"
|
||||
|
||||
} else {
|
||||
x.a = "1";
|
||||
>x.a = "1" : "1"
|
||||
>x.a : any
|
||||
>x : B
|
||||
>a : any
|
||||
>"1" : "1"
|
||||
}
|
||||
}
|
||||
|
||||
class ClassWithUnionProp { prop: A | B }
|
||||
>ClassWithUnionProp : ClassWithUnionProp
|
||||
>prop : A | B
|
||||
|
||||
function negativePropTest(x: ClassWithUnionProp) {
|
||||
>negativePropTest : (x: ClassWithUnionProp) => void
|
||||
>x : ClassWithUnionProp
|
||||
|
||||
if ("a" in x.prop) {
|
||||
>"a" in x.prop : boolean
|
||||
>"a" : "a"
|
||||
>x.prop : A | B
|
||||
>x : ClassWithUnionProp
|
||||
>prop : A | B
|
||||
|
||||
let y: string = x.prop.b;
|
||||
>y : string
|
||||
>x.prop.b : any
|
||||
>x.prop : A
|
||||
>x : ClassWithUnionProp
|
||||
>prop : A
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
let z: string = x.prop.a;
|
||||
>z : string
|
||||
>x.prop.a : any
|
||||
>x.prop : B
|
||||
>x : ClassWithUnionProp
|
||||
>prop : B
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
|
||||
class NegativeClassTest {
|
||||
>NegativeClassTest : NegativeClassTest
|
||||
|
||||
protected prop: A | B;
|
||||
>prop : A | B
|
||||
|
||||
inThis() {
|
||||
>inThis : () => void
|
||||
|
||||
if ("a" in this.prop) {
|
||||
>"a" in this.prop : boolean
|
||||
>"a" : "a"
|
||||
>this.prop : A | B
|
||||
>this : this
|
||||
>prop : A | B
|
||||
|
||||
let z: number = this.prop.b;
|
||||
>z : number
|
||||
>this.prop.b : any
|
||||
>this.prop : A
|
||||
>this : this
|
||||
>prop : A
|
||||
>b : any
|
||||
|
||||
} else {
|
||||
let y: string = this.prop.a;
|
||||
>y : string
|
||||
>this.prop.a : any
|
||||
>this.prop : B
|
||||
>this : this
|
||||
>prop : B
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UnreachableCodeDetection {
|
||||
>UnreachableCodeDetection : UnreachableCodeDetection
|
||||
|
||||
a: string;
|
||||
>a : string
|
||||
|
||||
inThis() {
|
||||
>inThis : () => void
|
||||
|
||||
if ("a" in this) {
|
||||
>"a" in this : boolean
|
||||
>"a" : "a"
|
||||
>this : this
|
||||
|
||||
} else {
|
||||
let y = this.a;
|
||||
>y : any
|
||||
>this.a : any
|
||||
>this : never
|
||||
>a : any
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function positiveIntersectionTest(x: { a: string } & { b: string }) {
|
||||
>positiveIntersectionTest : (x: { a: string;} & { b: string;}) => void
|
||||
>x : { a: string; } & { b: string; }
|
||||
>a : string
|
||||
>b : string
|
||||
|
||||
if ("a" in x) {
|
||||
>"a" in x : boolean
|
||||
>"a" : "a"
|
||||
>x : { a: string; } & { b: string; }
|
||||
|
||||
let s: string = x.a;
|
||||
>s : string
|
||||
>x.a : string
|
||||
>x : { a: string; } & { b: string; }
|
||||
>a : string
|
||||
|
||||
} else {
|
||||
let n: never = x;
|
||||
>n : never
|
||||
>x : never
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #38608
|
||||
declare const error: Error;
|
||||
>error : Error
|
||||
|
||||
if ('extra' in error) {
|
||||
>'extra' in error : boolean
|
||||
>'extra' : "extra"
|
||||
>error : Error
|
||||
|
||||
error // Still Error
|
||||
>error : Error
|
||||
|
||||
} else {
|
||||
error // Error
|
||||
>error : Error
|
||||
}
|
||||
|
||||
function narrowsToNever(x: { l: number } | { r: number }) {
|
||||
>narrowsToNever : (x: { l: number;} | { r: number;}) => number
|
||||
>x : { l: number; } | { r: number; }
|
||||
>l : number
|
||||
>r : number
|
||||
|
||||
let v: number;
|
||||
>v : number
|
||||
|
||||
if ("l" in x) {
|
||||
>"l" in x : boolean
|
||||
>"l" : "l"
|
||||
>x : { l: number; } | { r: number; }
|
||||
|
||||
v = x.l;
|
||||
>v = x.l : number
|
||||
>v : number
|
||||
>x.l : number
|
||||
>x : { l: number; }
|
||||
>l : number
|
||||
}
|
||||
else if ("r" in x) {
|
||||
>"r" in x : boolean
|
||||
>"r" : "r"
|
||||
>x : { r: number; }
|
||||
|
||||
v = x.r;
|
||||
>v = x.r : number
|
||||
>v : number
|
||||
>x.r : number
|
||||
>x : { r: number; }
|
||||
>r : number
|
||||
}
|
||||
else {
|
||||
v = x
|
||||
>v = x : never
|
||||
>v : number
|
||||
>x : never
|
||||
}
|
||||
return v;
|
||||
>v : number
|
||||
}
|
||||
|
||||
type AOrB = { aProp: number } | { bProp: number };
|
||||
>AOrB : { aProp: number; } | { bProp: number; }
|
||||
>aProp : number
|
||||
>bProp : number
|
||||
|
||||
declare function isAOrB(x: unknown): x is AOrB;
|
||||
>isAOrB : (x: unknown) => x is AOrB
|
||||
>x : unknown
|
||||
|
||||
declare var x: unknown;
|
||||
>x : unknown
|
||||
|
||||
if (isAOrB(x)) {
|
||||
>isAOrB(x) : boolean
|
||||
>isAOrB : (x: unknown) => x is AOrB
|
||||
>x : unknown
|
||||
|
||||
if ("aProp" in x) {
|
||||
>"aProp" in x : boolean
|
||||
>"aProp" : "aProp"
|
||||
>x : AOrB
|
||||
|
||||
x.aProp;
|
||||
>x.aProp : number
|
||||
>x : { aProp: number; }
|
||||
>aProp : number
|
||||
}
|
||||
else if ("bProp" in x) {
|
||||
>"bProp" in x : boolean
|
||||
>"bProp" : "bProp"
|
||||
>x : { bProp: number; }
|
||||
|
||||
x.bProp;
|
||||
>x.bProp : number
|
||||
>x : { bProp: number; }
|
||||
>bProp : number
|
||||
}
|
||||
// x is never because of the type predicate from unknown
|
||||
else if ("cProp" in x) {
|
||||
>"cProp" in x : boolean
|
||||
>"cProp" : "cProp"
|
||||
>x : never
|
||||
|
||||
const _never: never = x;
|
||||
>_never : never
|
||||
>x : never
|
||||
}
|
||||
}
|
||||
|
||||
function negativeIntersectionTest() {
|
||||
>negativeIntersectionTest : () => void
|
||||
|
||||
if ("ontouchstart" in window) {
|
||||
>"ontouchstart" in window : boolean
|
||||
>"ontouchstart" : "ontouchstart"
|
||||
>window : Window & typeof globalThis
|
||||
|
||||
window.ontouchstart
|
||||
>window.ontouchstart : ((this: GlobalEventHandlers, ev: TouchEvent) => any) & ((this: Window, ev: TouchEvent) => any)
|
||||
>window : Window & typeof globalThis
|
||||
>ontouchstart : ((this: GlobalEventHandlers, ev: TouchEvent) => any) & ((this: Window, ev: TouchEvent) => any)
|
||||
|
||||
} else {
|
||||
window.ontouchstart
|
||||
>window.ontouchstart : ((this: GlobalEventHandlers, ev: TouchEvent) => any) & ((this: Window, ev: TouchEvent) => any)
|
||||
>window : Window & typeof globalThis
|
||||
>ontouchstart : ((this: GlobalEventHandlers, ev: TouchEvent) => any) & ((this: Window, ev: TouchEvent) => any)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
tests/cases/compiler/inOperator.ts(7,15): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/compiler/inOperator.ts(7,15): error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/inOperator.ts (1 errors) ====
|
||||
@ -10,7 +10,7 @@ tests/cases/compiler/inOperator.ts(7,15): error TS2361: The right-hand side of a
|
||||
|
||||
var b = '' in 0;
|
||||
~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
|
||||
var c: any;
|
||||
var y: number;
|
||||
|
||||
@ -1,24 +1,26 @@
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(15,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(16,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(17,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(15,11): error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(16,11): error TS2322: Type 'void' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(17,11): error TS2322: Type '{}' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(19,11): error TS18050: The value 'null' cannot be used here.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(20,11): error TS18050: The value 'undefined' cannot be used here.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(22,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(23,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(24,12): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(25,12): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(35,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(36,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(37,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(38,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(39,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(40,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(41,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(42,16): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(22,11): error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(23,11): error TS2322: Type '{}' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(24,12): error TS2322: Type 'string | Foo' is not assignable to type 'string | number | symbol'.
|
||||
Type 'Foo' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(25,12): error TS2322: Type 'Foo' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(35,16): error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(36,16): error TS2322: Type 'boolean' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(37,16): error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(38,16): error TS2322: Type 'void' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(39,16): error TS2322: Type 'string | number' is not assignable to type 'object'.
|
||||
Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(40,16): error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(41,16): error TS2322: Type 'boolean' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(42,16): error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(43,16): error TS18050: The value 'null' cannot be used here.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(44,17): error TS18050: The value 'undefined' cannot be used here.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(47,11): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(47,17): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(47,11): error TS2322: Type '{}' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(47,17): error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts (21 errors) ====
|
||||
@ -38,13 +40,13 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
||||
|
||||
var ra1 = a1 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
var ra2 = a2 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type 'void' is not assignable to type 'string | number | symbol'.
|
||||
var ra3 = a3 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'string | number | symbol'.
|
||||
var ra4 = a4 in x;
|
||||
var ra5 = null in x;
|
||||
~~~~
|
||||
@ -55,16 +57,17 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
||||
var ra7 = E.a in x;
|
||||
var ra8 = false in x;
|
||||
~~~~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
var ra9 = {} in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'string | number | symbol'.
|
||||
var ra10 = a5 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type 'string | Foo' is not assignable to type 'string | number | symbol'.
|
||||
!!! error TS2322: Type 'Foo' is not assignable to type 'string | number | symbol'.
|
||||
var ra11 = a6 in x;
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type 'Foo' is not assignable to type 'string | number | symbol'.
|
||||
|
||||
// invalid right operands
|
||||
// the right operand is required to be of type Any, an object type, or a type parameter type
|
||||
@ -76,28 +79,29 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
||||
|
||||
var rb1 = x in b1;
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
var rb2 = x in b2;
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'boolean' is not assignable to type 'object'.
|
||||
var rb3 = x in b3;
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
var rb4 = x in b4;
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'void' is not assignable to type 'object'.
|
||||
var rb5 = x in b5;
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'string | number' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
var rb6 = x in 0;
|
||||
~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
var rb7 = x in false;
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'boolean' is not assignable to type 'object'.
|
||||
var rb8 = x in '';
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
var rb9 = x in null;
|
||||
~~~~
|
||||
!!! error TS18050: The value 'null' cannot be used here.
|
||||
@ -108,6 +112,6 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
||||
// both operands are invalid
|
||||
var rc1 = {} in '';
|
||||
~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type '{}' is not assignable to type 'string | number | symbol'.
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
@ -0,0 +1,65 @@
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithValidOperands.ts(26,20): error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithValidOperands.ts(30,20): error TS2322: Type 'T | U' is not assignable to type 'object'.
|
||||
Type 'T' is not assignable to type 'object'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithValidOperands.ts(34,20): error TS2322: Type 'object | T' is not assignable to type 'object'.
|
||||
Type 'T' is not assignable to type 'object'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithValidOperands.ts (3 errors) ====
|
||||
var x: any;
|
||||
|
||||
// valid left operands
|
||||
// the left operand is required to be of type Any, the String primitive type, or the Number primitive type
|
||||
var a1: string;
|
||||
var a2: number;
|
||||
var a3: string | number | symbol;
|
||||
var a4: any;
|
||||
|
||||
var ra1 = x in x;
|
||||
var ra2 = a1 in x;
|
||||
var ra3 = a2 in x;
|
||||
var ra4 = '' in x;
|
||||
var ra5 = 0 in x;
|
||||
var ra6 = a3 in x;
|
||||
var ra7 = a4 in x;
|
||||
|
||||
// valid right operands
|
||||
// the right operand is required to be of type Any, an object type, or a type parameter type
|
||||
var b1: {};
|
||||
|
||||
var rb1 = x in b1;
|
||||
var rb2 = x in {};
|
||||
|
||||
function foo<T>(t: T) {
|
||||
var rb3 = x in t;
|
||||
~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithValidOperands.ts:25:14: This type parameter might need an `extends object` constraint.
|
||||
}
|
||||
|
||||
function unionCase<T, U>(t: T | U) {
|
||||
var rb4 = x in t;
|
||||
~
|
||||
!!! error TS2322: Type 'T | U' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithValidOperands.ts:29:20: This type parameter might need an `extends object` constraint.
|
||||
}
|
||||
|
||||
function unionCase2<T>(t: T | object) {
|
||||
var rb5 = x in t;
|
||||
~
|
||||
!!! error TS2322: Type 'object | T' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'object'.
|
||||
!!! related TS2208 tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithValidOperands.ts:33:21: This type parameter might need an `extends object` constraint.
|
||||
}
|
||||
|
||||
interface X { x: number }
|
||||
interface Y { y: number }
|
||||
|
||||
var c1: X | Y;
|
||||
var c2: X;
|
||||
var c3: Y;
|
||||
|
||||
var rc1 = x in c1;
|
||||
var rc2 = x in (c2 || c3);
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(205,24): error TS2322: Type 'T[keyof T]' is not assignable to type 'object'.
|
||||
Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'object'.
|
||||
Type 'T[string]' is not assignable to type 'object'.
|
||||
tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(211,24): error TS2322: Type 'T[K]' is not assignable to type 'object'.
|
||||
Type 'T[keyof T]' is not assignable to type 'object'.
|
||||
Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'object'.
|
||||
Type 'T[string]' is not assignable to type 'object'.
|
||||
tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(316,5): error TS2322: Type 'T' is not assignable to type '{}'.
|
||||
tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(317,5): error TS2322: Type 'T[keyof T]' is not assignable to type '{}'.
|
||||
Type 'T[string] | T[number] | T[symbol]' is not assignable to type '{}'.
|
||||
@ -6,7 +13,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(318,5): error TS232
|
||||
Type 'T[keyof T]' is not assignable to type '{}'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts (3 errors) ====
|
||||
==== tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts (5 errors) ====
|
||||
class Shape {
|
||||
name: string;
|
||||
width: number;
|
||||
@ -212,12 +219,21 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts(318,5): error TS232
|
||||
for (let s in obj[key]) {
|
||||
}
|
||||
const b = "foo" in obj[key];
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T[string]' is not assignable to type 'object'.
|
||||
}
|
||||
|
||||
function f55<T, K extends keyof T>(obj: T, key: K) {
|
||||
for (let s in obj[key]) {
|
||||
}
|
||||
const b = "foo" in obj[key];
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type 'T[K]' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T[keyof T]' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T[string] | T[number] | T[symbol]' is not assignable to type 'object'.
|
||||
!!! error TS2322: Type 'T[string]' is not assignable to type 'object'.
|
||||
}
|
||||
|
||||
function f60<T>(source: T, target: T) {
|
||||
|
||||
@ -10,7 +10,7 @@ tests/cases/conformance/types/mapped/mappedTypeProperties.ts(37,5): error TS7061
|
||||
tests/cases/conformance/types/mapped/mappedTypeProperties.ts(40,5): error TS1166: A computed property name in a class property declaration must have a simple literal type or a 'unique symbol' type.
|
||||
tests/cases/conformance/types/mapped/mappedTypeProperties.ts(40,6): error TS2304: Cannot find name 'P'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeProperties.ts(40,6): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
|
||||
tests/cases/conformance/types/mapped/mappedTypeProperties.ts(40,11): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/types/mapped/mappedTypeProperties.ts(40,11): error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeProperties.ts(40,17): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ tests/cases/conformance/types/mapped/mappedTypeProperties.ts(40,17): error TS236
|
||||
~~~~~~~~
|
||||
!!! error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
|
||||
~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'object'.
|
||||
~~~
|
||||
!!! error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(20,24): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(24,14): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(20,24): error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(24,14): error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(29,21): error TS1005: ';' expected.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(30,21): error TS1005: ';' expected.
|
||||
|
||||
@ -26,13 +26,13 @@ tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTr
|
||||
|
||||
v << #field in v << v; // Good precedence (SyntaxError): (v << #field) in (v << v)
|
||||
~~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in v)
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
|
||||
#field in v && #field in v; // Good precedence: (#field in v) && (#field in v)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(20,24): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(24,14): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(20,24): error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(24,14): error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(29,21): error TS1005: ';' expected.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(30,21): error TS1005: ';' expected.
|
||||
|
||||
@ -26,13 +26,13 @@ tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTr
|
||||
|
||||
v << #field in v << v; // Good precedence (SyntaxError): (v << #field) in (v << v)
|
||||
~~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in v)
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
|
||||
#field in v && #field in v; // Good precedence: (#field in v) && (#field in v)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(20,24): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(24,14): error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(20,24): error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(24,14): error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(29,21): error TS1005: ';' expected.
|
||||
tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTransform.ts(30,21): error TS1005: ';' expected.
|
||||
|
||||
@ -26,13 +26,13 @@ tests/cases/conformance/classes/members/privateNames/privateNameInInExpressionTr
|
||||
|
||||
v << #field in v << v; // Good precedence (SyntaxError): (v << #field) in (v << v)
|
||||
~~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'object'.
|
||||
|
||||
v << #field in v == v; // Good precedence (SyntaxError): ((v << #field) in v) == v
|
||||
|
||||
v == #field in v in v; // Good precedence: v == ((#field in v) in v)
|
||||
~~~~~~~~~~~
|
||||
!!! error TS2360: The left-hand side of an 'in' expression must be a private identifier or of type 'any', 'string', 'number', or 'symbol'.
|
||||
!!! error TS2322: Type 'boolean' is not assignable to type 'string | number | symbol'.
|
||||
|
||||
#field in v && #field in v; // Good precedence: (#field in v) && (#field in v)
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
tests/cases/conformance/es6/Symbols/symbolType2.ts(2,7): error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
tests/cases/conformance/es6/Symbols/symbolType2.ts(2,7): error TS2322: Type 'typeof Symbol.toPrimitive' is not assignable to type 'object'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/Symbols/symbolType2.ts (1 errors) ====
|
||||
Symbol.isConcatSpreadable in {};
|
||||
"" in Symbol.toPrimitive;
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must not be a primitive.
|
||||
!!! error TS2322: Type 'typeof Symbol.toPrimitive' is not assignable to type 'object'.
|
||||
@ -1,3 +1,6 @@
|
||||
// @strict: true, false
|
||||
// @target: es2015
|
||||
|
||||
class A { a: string; }
|
||||
class B { b: string; }
|
||||
|
||||
@ -150,3 +153,130 @@ function negativeIntersectionTest() {
|
||||
window.ontouchstart
|
||||
}
|
||||
}
|
||||
|
||||
function f1(x: unknown) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: object) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f3<T>(x: T) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if (x && typeof x === "object" && "a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f4(x: { a: string }) {
|
||||
if ("a" in x) {
|
||||
x.a;
|
||||
}
|
||||
if ("a" in x && "b" in x && "c" in x) {
|
||||
x.a;
|
||||
x.b;
|
||||
x.c;
|
||||
}
|
||||
}
|
||||
|
||||
function f5(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("b" in x) {
|
||||
x; // { b: string }
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
}
|
||||
|
||||
function f6(x: { a: string } | { b: string }) {
|
||||
if ("a" in x) {
|
||||
x; // { a: string }
|
||||
}
|
||||
else if ("a" in x) {
|
||||
x; // { b: string } & Record<"a", unknown>
|
||||
}
|
||||
else {
|
||||
x; // { b: string }
|
||||
}
|
||||
}
|
||||
|
||||
// Object and corresponding intersection should narrow the same
|
||||
|
||||
function f7(x: { a: string, b: number }, y: { a: string } & { b: number }) {
|
||||
if ("a" in x) {
|
||||
x;
|
||||
}
|
||||
else {
|
||||
x; // never
|
||||
}
|
||||
if ("a" in y) {
|
||||
y;
|
||||
}
|
||||
else {
|
||||
y; // never
|
||||
}
|
||||
}
|
||||
|
||||
const sym = Symbol();
|
||||
|
||||
function f8(x: object) {
|
||||
if ("a" in x && 1 in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
function f9(x: object) {
|
||||
if ("a" in x && "1" in x && sym in x) {
|
||||
x.a;
|
||||
x["a"];
|
||||
x[1];
|
||||
x["1"];
|
||||
x[sym];
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #50639
|
||||
|
||||
function foo<A>(value: A) {
|
||||
if (typeof value === "object" && value !== null && "prop" in value) {
|
||||
value; // A & object & Record<"prop", unknown>
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user