mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-10 18:04:18 -05:00
Add tests
This commit is contained in:
@@ -40,3 +40,17 @@ function foo5(bar: "a" | "b"): number {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
function foo6(bar: "a", a: boolean, b: boolean): number {
|
||||
if (a) {
|
||||
switch (bar) {
|
||||
case "a": return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (b) {
|
||||
case true: return -1;
|
||||
case false: return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
128
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts
Normal file
128
tests/cases/conformance/controlFlow/assertionTypePredicates1.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
// @strict: true
|
||||
// @declaration: true
|
||||
|
||||
declare function isString(value: unknown): value is string;
|
||||
declare function isArrayOfStrings(value: unknown): value is string[];
|
||||
|
||||
const assert: (value: unknown) => asserts value = value => {}
|
||||
|
||||
declare function assertIsString(value: unknown): asserts value is string;
|
||||
declare function assertIsArrayOfStrings(value: unknown): asserts value is string[];
|
||||
declare function assertDefined<T>(value: T): asserts value is NonNullable<T>;
|
||||
|
||||
function f01(x: unknown) {
|
||||
if (!!true) {
|
||||
assert(typeof x === "string");
|
||||
x.length;
|
||||
}
|
||||
if (!!true) {
|
||||
assert(x instanceof Error);
|
||||
x.message;
|
||||
}
|
||||
if (!!true) {
|
||||
assert(typeof x === "boolean" || typeof x === "number");
|
||||
x.toLocaleString;
|
||||
}
|
||||
if (!!true) {
|
||||
assert(isArrayOfStrings(x));
|
||||
x[0].length;
|
||||
}
|
||||
if (!!true) {
|
||||
assertIsArrayOfStrings(x);
|
||||
x[0].length;
|
||||
}
|
||||
if (!!true) {
|
||||
assert(x === undefined || typeof x === "string");
|
||||
x; // string | undefined
|
||||
assertDefined(x);
|
||||
x; // string
|
||||
}
|
||||
}
|
||||
|
||||
function f02(x: string | undefined) {
|
||||
if (!!true) {
|
||||
assert(x);
|
||||
x.length;
|
||||
}
|
||||
if (!!true) {
|
||||
assert(x !== undefined);
|
||||
x.length;
|
||||
}
|
||||
if (!!true) {
|
||||
assertDefined(x);
|
||||
x.length;
|
||||
}
|
||||
}
|
||||
|
||||
function f03(x: string | undefined, assert: (value: unknown) => asserts value) {
|
||||
assert(x);
|
||||
x.length;
|
||||
}
|
||||
|
||||
namespace Debug {
|
||||
export declare function assert(value: unknown, message?: string): asserts value;
|
||||
export declare function assertDefined<T>(value: T): asserts value is NonNullable<T>;
|
||||
}
|
||||
|
||||
function f10(x: string | undefined) {
|
||||
if (!!true) {
|
||||
Debug.assert(x);
|
||||
x.length;
|
||||
}
|
||||
if (!!true) {
|
||||
Debug.assert(x !== undefined);
|
||||
x.length;
|
||||
}
|
||||
if (!!true) {
|
||||
Debug.assertDefined(x);
|
||||
x.length;
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
assert(value: unknown): asserts value {
|
||||
if (value) return;
|
||||
throw new Error();
|
||||
}
|
||||
isTest2(): this is Test2 {
|
||||
return this instanceof Test2;
|
||||
}
|
||||
assertIsTest2(): asserts this is Test2 {
|
||||
if (this instanceof Test2) return;
|
||||
throw new Error();
|
||||
}
|
||||
assertThis(): asserts this {
|
||||
if (!this) return;
|
||||
throw new Error();
|
||||
}
|
||||
bar() {
|
||||
this.assertThis();
|
||||
this;
|
||||
}
|
||||
foo(x: unknown) {
|
||||
this.assert(typeof x === "string");
|
||||
x.length;
|
||||
if (this.isTest2()) {
|
||||
this.z;
|
||||
}
|
||||
this.assertIsTest2();
|
||||
this.z;
|
||||
}
|
||||
}
|
||||
|
||||
class Test2 extends Test {
|
||||
z = 0;
|
||||
}
|
||||
|
||||
// Invalid constructs
|
||||
|
||||
declare let Q1: new (x: unknown) => x is string;
|
||||
declare let Q2: new (x: boolean) => asserts x;
|
||||
declare let Q3: new (x: unknown) => asserts x is string;
|
||||
|
||||
declare class Wat {
|
||||
get p1(): this is string;
|
||||
set p1(x: this is string);
|
||||
get p2(): asserts this is string;
|
||||
set p2(x: asserts this is string);
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
// @strict: true
|
||||
// @allowUnreachableCode: false
|
||||
// @declaration: true
|
||||
|
||||
function f1(x: 1 | 2): string {
|
||||
if (!!true) {
|
||||
switch (x) {
|
||||
case 1: return 'a';
|
||||
case 2: return 'b';
|
||||
}
|
||||
x; // Unreachable
|
||||
}
|
||||
else {
|
||||
throw 0;
|
||||
}
|
||||
}
|
||||
|
||||
function f2(x: 1 | 2) {
|
||||
let z: number;
|
||||
switch (x) {
|
||||
case 1: z = 10; break;
|
||||
case 2: z = 20; break;
|
||||
}
|
||||
z; // Definitely assigned
|
||||
}
|
||||
|
||||
function f3(x: 1 | 2) {
|
||||
switch (x) {
|
||||
case 1: return 10;
|
||||
case 2: return 20;
|
||||
// Default considered reachable to allow defensive coding
|
||||
default: throw new Error("Bad input");
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #11572
|
||||
|
||||
enum E { A, B }
|
||||
|
||||
function f(e: E): number {
|
||||
switch (e) {
|
||||
case E.A: return 0
|
||||
case E.B: return 1
|
||||
}
|
||||
}
|
||||
|
||||
function g(e: E): number {
|
||||
if (!true)
|
||||
return -1
|
||||
else
|
||||
switch (e) {
|
||||
case E.A: return 0
|
||||
case E.B: return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #12668
|
||||
|
||||
interface Square { kind: "square"; size: number; }
|
||||
|
||||
interface Rectangle { kind: "rectangle"; width: number; height: number; }
|
||||
|
||||
interface Circle { kind: "circle"; radius: number; }
|
||||
|
||||
interface Triangle { kind: "triangle"; side: number; }
|
||||
|
||||
type Shape = Square | Rectangle | Circle | Triangle;
|
||||
|
||||
function area(s: Shape): number {
|
||||
let area;
|
||||
switch (s.kind) {
|
||||
case "square": area = s.size * s.size; break;
|
||||
case "rectangle": area = s.width * s.height; break;
|
||||
case "circle": area = Math.PI * s.radius * s.radius; break;
|
||||
case "triangle": area = Math.sqrt(3) / 4 * s.side * s.side; break;
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
||||
function areaWrapped(s: Shape): number {
|
||||
let area;
|
||||
area = (() => {
|
||||
switch (s.kind) {
|
||||
case "square": return s.size * s.size;
|
||||
case "rectangle": return s.width * s.height;
|
||||
case "circle": return Math.PI * s.radius * s.radius;
|
||||
case "triangle": return Math.sqrt(3) / 4 * s.side * s.side;
|
||||
}
|
||||
})();
|
||||
return area;
|
||||
}
|
||||
|
||||
// Repro from #13241
|
||||
|
||||
enum MyEnum {
|
||||
A,
|
||||
B
|
||||
}
|
||||
|
||||
function thisGivesError(e: MyEnum): string {
|
||||
let s: string;
|
||||
switch (e) {
|
||||
case MyEnum.A: s = "it was A"; break;
|
||||
case MyEnum.B: s = "it was B"; break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function good1(e: MyEnum): string {
|
||||
let s: string;
|
||||
switch (e) {
|
||||
case MyEnum.A: s = "it was A"; break;
|
||||
case MyEnum.B: s = "it was B"; break;
|
||||
default: s = "it was something else"; break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function good2(e: MyEnum): string {
|
||||
switch (e) {
|
||||
case MyEnum.A: return "it was A";
|
||||
case MyEnum.B: return "it was B";
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #18362
|
||||
|
||||
enum Level {
|
||||
One,
|
||||
Two,
|
||||
}
|
||||
|
||||
const doSomethingWithLevel = (level: Level) => {
|
||||
let next: Level;
|
||||
switch (level) {
|
||||
case Level.One:
|
||||
next = Level.Two;
|
||||
break;
|
||||
case Level.Two:
|
||||
next = Level.One;
|
||||
break;
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
// Repro from #20409
|
||||
|
||||
interface Square2 {
|
||||
kind: "square";
|
||||
size: number;
|
||||
}
|
||||
|
||||
interface Circle2 {
|
||||
kind: "circle";
|
||||
radius: number;
|
||||
}
|
||||
|
||||
type Shape2 = Square2 | Circle2;
|
||||
|
||||
function withDefault(s1: Shape2, s2: Shape2): string {
|
||||
switch (s1.kind) {
|
||||
case "square":
|
||||
return "1";
|
||||
case "circle":
|
||||
switch (s2.kind) {
|
||||
case "square":
|
||||
return "2";
|
||||
case "circle":
|
||||
return "3";
|
||||
default:
|
||||
return "never";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function withoutDefault(s1: Shape2, s2: Shape2): string {
|
||||
switch (s1.kind) {
|
||||
case "square":
|
||||
return "1";
|
||||
case "circle":
|
||||
switch (s2.kind) {
|
||||
case "square":
|
||||
return "2";
|
||||
case "circle":
|
||||
return "3";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Repro from #20823
|
||||
|
||||
function test4(value: 1 | 2) {
|
||||
let x: string;
|
||||
switch (value) {
|
||||
case 1: x = "one"; break;
|
||||
case 2: x = "two"; break;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
158
tests/cases/conformance/controlFlow/neverReturningFunctions1.ts
Normal file
158
tests/cases/conformance/controlFlow/neverReturningFunctions1.ts
Normal file
@@ -0,0 +1,158 @@
|
||||
// @strict: true
|
||||
// @allowUnreachableCode: false
|
||||
// @declaration: true
|
||||
|
||||
function fail(message?: string): never {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
function f01(x: string | undefined) {
|
||||
if (x === undefined) fail("undefined argument");
|
||||
x.length; // string
|
||||
}
|
||||
|
||||
function f02(x: number): number {
|
||||
if (x >= 0) return x;
|
||||
fail("negative number");
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
function f03(x: string) {
|
||||
x; // string
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
function f11(x: string | undefined, fail: (message?: string) => never) {
|
||||
if (x === undefined) fail("undefined argument");
|
||||
x.length; // string
|
||||
}
|
||||
|
||||
function f12(x: number, fail: (message?: string) => never): number {
|
||||
if (x >= 0) return x;
|
||||
fail("negative number");
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
function f13(x: string, fail: (message?: string) => never) {
|
||||
x; // string
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
namespace Debug {
|
||||
export declare function fail(message?: string): never;
|
||||
}
|
||||
|
||||
function f21(x: string | undefined) {
|
||||
if (x === undefined) Debug.fail("undefined argument");
|
||||
x.length; // string
|
||||
}
|
||||
|
||||
function f22(x: number): number {
|
||||
if (x >= 0) return x;
|
||||
Debug.fail("negative number");
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
function f23(x: string) {
|
||||
x; // string
|
||||
Debug.fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
function f24(x: string) {
|
||||
x; // string
|
||||
((Debug).fail)();
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
class Test {
|
||||
fail(message?: string): never {
|
||||
throw new Error(message);
|
||||
}
|
||||
f1(x: string | undefined) {
|
||||
if (x === undefined) this.fail("undefined argument");
|
||||
x.length; // string
|
||||
}
|
||||
f2(x: number): number {
|
||||
if (x >= 0) return x;
|
||||
this.fail("negative number");
|
||||
x; // Unreachable
|
||||
}
|
||||
f3(x: string) {
|
||||
x; // string
|
||||
this.fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
}
|
||||
|
||||
function f30(x: string | number | undefined) {
|
||||
if (typeof x === "string") {
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
else {
|
||||
x; // number | undefined
|
||||
if (x !== undefined) {
|
||||
x; // number
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
else {
|
||||
x; // undefined
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
x; // Unreachable
|
||||
}
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
function f31(x: { a: string | number }) {
|
||||
if (typeof x.a === "string") {
|
||||
fail();
|
||||
x; // Unreachable
|
||||
x.a; // Unreachable
|
||||
}
|
||||
x; // { a: string | number }
|
||||
x.a; // number
|
||||
}
|
||||
|
||||
function f40(x: number) {
|
||||
try {
|
||||
x;
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
finally {
|
||||
x;
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
function f41(x: number) {
|
||||
try {
|
||||
x;
|
||||
}
|
||||
finally {
|
||||
x;
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
x; // Unreachable
|
||||
}
|
||||
|
||||
function f42(x: number) {
|
||||
try {
|
||||
x;
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
finally {
|
||||
x;
|
||||
}
|
||||
x; // Unreachable
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
// @allowUnreachableCode: false
|
||||
// @filename: assertionsAndNonReturningFunctions.js
|
||||
|
||||
/** @typedef {(check: boolean) => asserts check} AssertFunc */
|
||||
|
||||
/** @type {AssertFunc} */
|
||||
const assert = check => {
|
||||
if (!check) throw new Error();
|
||||
}
|
||||
|
||||
/** @type {(x: unknown) => asserts x is string } */
|
||||
function assertIsString(x) {
|
||||
if (!(typeof x === "string")) throw new Error();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} check
|
||||
* @returns {asserts check}
|
||||
*/
|
||||
function assert2(check) {
|
||||
if (!check) throw new Error();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {never}
|
||||
*/
|
||||
function fail() {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} x
|
||||
*/
|
||||
function f1(x) {
|
||||
if (!!true) {
|
||||
assert(typeof x === "string");
|
||||
x.length;
|
||||
}
|
||||
if (!!true) {
|
||||
assert2(typeof x === "string");
|
||||
x.length;
|
||||
}
|
||||
if (!!true) {
|
||||
assertIsString(x);
|
||||
x.length;
|
||||
}
|
||||
if (!!true) {
|
||||
fail();
|
||||
x; // Unreachable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} b
|
||||
*/
|
||||
function f2(b) {
|
||||
switch (b) {
|
||||
case true: return 1;
|
||||
case false: return 0;
|
||||
}
|
||||
b; // Unreachable
|
||||
}
|
||||
Reference in New Issue
Block a user