Skip to content

Commit

Permalink
add test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
ShuiRuTian committed Jun 7, 2020
1 parent 762a027 commit 52a8e26
Show file tree
Hide file tree
Showing 12 changed files with 416 additions and 128 deletions.
19 changes: 8 additions & 11 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21203,7 +21203,8 @@ namespace ts {
let notNullOrUndefinedFilter = false; // the aim of this filter is type has 'undefined',filter it out from result.
const isExpressionContainOptionalChain = isAccessExpressionContainOptionalChain(typeOfExpr.expression);
// ~undefined means other values except undefiend. boolean, bigint....
if (assumeTrue && literal.text !== "undefined") {
if ((assumeTrue && literal.text !== "undefined")||(!assumeTrue && literal.text === "undefined")) {
// !== undefined
// === ~undefined
// use full expression to narrow
propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, typeOfExpr.expression,/* optionalChainSlice */ false);
Expand All @@ -21213,10 +21214,6 @@ namespace ts {
// !== ~undefined, === undefined, !==undefined
// use non-OptionalChain part to narrow
propertyTypeArray = narrowUnionTypeWithPropertyPathAndExpression(<UnionType>type, typeOfExpr.expression,/* optionalChainSlice */ true);
if (!assumeTrue && literal.text === "undefined") {
// !== undefined
notNullOrUndefinedFilter = true;
}
if (isExpressionContainOptionalChain) {
facts = TypeFacts.None; // The aim is no filter.
}
Expand Down Expand Up @@ -29673,12 +29670,12 @@ namespace ts {
}
// If a type has been cached for the node, return it.
// Note: this is not only cache, without this, some test case would always runs, such as binaryArithmeticControlFlowGraphNotTooLarge.
if (node.flags & NodeFlags.TypeCached && flowTypeCache) {
const cachedType = flowTypeCache[getNodeId(node)];
if (cachedType) {
return cachedType;
}
}
// if (node.flags & NodeFlags.TypeCached && flowTypeCache) {
// const cachedType = flowTypeCache[getNodeId(node)];
// if (cachedType) {
// return cachedType;
// }
// }
const startInvocationCount = flowInvocationCount;
const type = checkExpression(node);
// If control flow analysis was required to determine the type, it is worth caching.
Expand Down
1 change: 1 addition & 0 deletions tests/baselines/reference/typeGuardAccordingToProperty.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ function f1_(u: Union1) {


//// [typeGuardAccordingToProperty.js]
"use strict";
// Primitive value ---- boolean bigint number string symbol undefined function object
// ts special type ---- any, void, unknown, union, intersection
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ function f2(u: Union2) {


//// [typeGuardAccordingToPropertyBySwitch.js]
"use strict";
function f(u) {
switch (typeof u.firstKey) {
case 'number':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ function f4(u: Union2) {


//// [typeGuardAccordingToPropertyDeep.js]
"use strict";
//// deep property access ---- a.b.c.d.e.f, a["b"]["c"]["d"]
//// mix deep property access ---- a.b["c"]["d"].e
function f(u) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(64,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(72,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(84,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(84,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(88,11): error TS2339: Property 'key1' does not exist on type 'never'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(96,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(96,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(103,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(103,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(115,9): error TS2532: Object is possibly 'undefined'.
tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts(115,9): error TS2532: Object is possibly 'undefined'.


==== tests/cases/conformance/expressions/typeGuards/typeGuardAccordingToPropertyOptional.ts (11 errors) ====
interface Foo1 {
key1:{
key2:number;
}|undefined;
f1: number;
}

interface Foo2 {
key1: {
key2:string
} | undefined;
f2: number;
}

interface Foo3 {
key1:{
key2:number;
};
f2: number;
}

type U1 = Foo1 | Foo2 | Foo3;
type U2 = Foo1 | Foo2 | Foo3|undefined;

// unnecessary optional chain
function f1(u: U1) {
if (typeof u?.key1 !== 'number') {
u; // U1
}
if (typeof u?.key1 === 'number') {
u; // never
}
if (typeof u?.key1 !== 'undefined') {
u; // U1
}
if (typeof u?.key1 === 'undefined') {
u; // U1
}
}

// non-root optional chain
function f2(u: U1) {
if (typeof u.key1?.key2 !== 'number') {
u; // U1
}
if (typeof u.key1?.key2 === 'number') {
u; // Foo1 | Foo3
}
if (typeof u.key1?.key2 !== 'undefined') {
u; // U1
}
if (typeof u.key1?.key2 === 'undefined') {
u; // U1
}
}

function f2Plus(u: U1){
if (typeof u.key1?.key2 === 'undefined' && typeof u.key1?.key2 === 'number') {
u; // Foo1 | Foo3
u.key1.key2;
}
if (typeof u.key1?.key2 === 'undefined' || typeof u.key1?.key2 === 'number') {
u; // U1
u.key1.key2; // Error
~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
if ( typeof u.key1?.key2 === 'number' && typeof u.key1?.key2 === 'undefined') {
u; // Foo1 | Foo3
u.key1.key2;
}
if ( typeof u.key1?.key2 === 'number' || typeof u.key1?.key2 === 'undefined') {
u; // U1
u.key1.key2; // Error
~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
if ( typeof u.key1?.key2 === 'number' || typeof u.key1?.key2 !== 'undefined') {
u; // U1
u.key1.key2;
}
}

// root optional chain
function f3(u: U2) {
if (typeof u?.key1 !== 'number') {
u; // U2
u.key1.key2;
~
!!! error TS2532: Object is possibly 'undefined'.
~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
if (typeof u?.key1 === 'number') {
u; // never
u.key1.key2;
~~~~
!!! error TS2339: Property 'key1' does not exist on type 'never'.
}
if (typeof u?.key1 !== 'undefined') {
u; // Foo1 | Foo2 | Foo3
u.key1.key2;
}
if (typeof u?.key1 === 'undefined') {
u; // U2
u.key1.key2;
~
!!! error TS2532: Object is possibly 'undefined'.
~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
}

function f4(u: U2) {
if (typeof u?.key1?.key2 !== 'number') {
u; // U2
u.key1.key2;
~
!!! error TS2532: Object is possibly 'undefined'.
~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
if (typeof u?.key1?.key2 === 'number') {
u; // Foo1 | Foo3
u.key1.key2;
}
if (typeof u?.key1?.key2 !== 'undefined') {
u; // Foo1 | Foo2 | Foo3
u.key1.key2;
}
if (typeof u?.key1?.key2 === 'undefined') {
u; // U2
u.key1.key2;
~
!!! error TS2532: Object is possibly 'undefined'.
~~~~~~
!!! error TS2532: Object is possibly 'undefined'.
}
}

17 changes: 17 additions & 0 deletions tests/baselines/reference/typeGuardAccordingToPropertyOptional.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,35 +82,44 @@ function f2Plus(u: U1){
function f3(u: U2) {
if (typeof u?.key1 !== 'number') {
u; // U2
u.key1.key2;
}
if (typeof u?.key1 === 'number') {
u; // never
u.key1.key2;
}
if (typeof u?.key1 !== 'undefined') {
u; // Foo1 | Foo2 | Foo3
u.key1.key2;
}
if (typeof u?.key1 === 'undefined') {
u; // U2
u.key1.key2;
}
}

function f4(u: U2) {
if (typeof u?.key1?.key2 !== 'number') {
u; // U2
u.key1.key2;
}
if (typeof u?.key1?.key2 === 'number') {
u; // Foo1 | Foo3
u.key1.key2;
}
if (typeof u?.key1?.key2 !== 'undefined') {
u; // Foo1 | Foo2 | Foo3
u.key1.key2;
}
if (typeof u?.key1?.key2 === 'undefined') {
u; // U2
u.key1.key2;
}
}


//// [typeGuardAccordingToPropertyOptional.js]
"use strict";
// unnecessary optional chain
function f1(u) {
if (typeof (u === null || u === void 0 ? void 0 : u.key1) !== 'number') {
Expand Down Expand Up @@ -169,29 +178,37 @@ function f2Plus(u) {
function f3(u) {
if (typeof (u === null || u === void 0 ? void 0 : u.key1) !== 'number') {
u; // U2
u.key1.key2;
}
if (typeof (u === null || u === void 0 ? void 0 : u.key1) === 'number') {
u; // never
u.key1.key2;
}
if (typeof (u === null || u === void 0 ? void 0 : u.key1) !== 'undefined') {
u; // Foo1 | Foo2 | Foo3
u.key1.key2;
}
if (typeof (u === null || u === void 0 ? void 0 : u.key1) === 'undefined') {
u; // U2
u.key1.key2;
}
}
function f4(u) {
var _a, _b, _c, _d;
if (typeof ((_a = u === null || u === void 0 ? void 0 : u.key1) === null || _a === void 0 ? void 0 : _a.key2) !== 'number') {
u; // U2
u.key1.key2;
}
if (typeof ((_b = u === null || u === void 0 ? void 0 : u.key1) === null || _b === void 0 ? void 0 : _b.key2) === 'number') {
u; // Foo1 | Foo3
u.key1.key2;
}
if (typeof ((_c = u === null || u === void 0 ? void 0 : u.key1) === null || _c === void 0 ? void 0 : _c.key2) !== 'undefined') {
u; // Foo1 | Foo2 | Foo3
u.key1.key2;
}
if (typeof ((_d = u === null || u === void 0 ? void 0 : u.key1) === null || _d === void 0 ? void 0 : _d.key2) === 'undefined') {
u; // U2
u.key1.key2;
}
}
Loading

0 comments on commit 52a8e26

Please sign in to comment.