mirror of
https://github.com/swc-project/swc.git
synced 2024-12-27 15:42:51 +03:00
454 lines
8.8 KiB
TypeScript
454 lines
8.8 KiB
TypeScript
// @strict: true
|
|
// @declaration: true
|
|
|
|
type T01 = {} & string; // {} & string
|
|
type T02 = {} & 'a'; // 'a'
|
|
type T03 = {} & object; // object
|
|
type T04 = {} & { x: number }; // { x: number }
|
|
type T05 = {} & null; // never
|
|
type T06 = {} & undefined; // never
|
|
type T07 = undefined & void; // undefined
|
|
|
|
type T10 = string & {}; // Specially preserved
|
|
type T11 = number & {}; // Specially preserved
|
|
type T12 = bigint & {}; // Specially preserved
|
|
|
|
type ThisNode = {};
|
|
type ThatNode = {};
|
|
type ThisOrThatNode = ThisNode | ThatNode;
|
|
|
|
function f01(u: unknown) {
|
|
let x1: {} = u; // Error
|
|
let x2: {} | null | undefined = u;
|
|
let x3: {} | { x: string } | null | undefined = u;
|
|
let x4: ThisOrThatNode | null | undefined = u;
|
|
}
|
|
|
|
function f10(x: unknown) {
|
|
if (x) {
|
|
x; // {}
|
|
}
|
|
else {
|
|
x; // unknown
|
|
}
|
|
if (!x) {
|
|
x; // unknown
|
|
}
|
|
else {
|
|
x; // {}
|
|
}
|
|
}
|
|
|
|
function f11<T>(x: T) {
|
|
if (x) {
|
|
x; // T & {}
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (!x) {
|
|
x; // T
|
|
}
|
|
else {
|
|
x; // T & {}
|
|
}
|
|
}
|
|
|
|
function f12<T extends {}>(x: T) {
|
|
if (x) {
|
|
x; // T
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
}
|
|
|
|
function f20(x: unknown) {
|
|
if (x !== undefined) {
|
|
x; // {} | null
|
|
}
|
|
else {
|
|
x; // undefined
|
|
}
|
|
if (x !== null) {
|
|
x; // {} | undefined
|
|
}
|
|
else {
|
|
x; // null
|
|
}
|
|
if (x !== undefined && x !== null) {
|
|
x; // {}
|
|
}
|
|
else {
|
|
x; // null | undefined
|
|
}
|
|
if (x != undefined) {
|
|
x; // {}
|
|
}
|
|
else {
|
|
x; // null | undefined
|
|
}
|
|
if (x != null) {
|
|
x; // {}
|
|
}
|
|
else {
|
|
x; // null | undefined
|
|
}
|
|
}
|
|
|
|
function f21<T>(x: T) {
|
|
if (x !== undefined) {
|
|
x; // T & ({} | null)
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (x !== null) {
|
|
x; // T & ({} | undefined)
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (x !== undefined && x !== null) {
|
|
x; // T & {}
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (x != undefined) {
|
|
x; // T & {}
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (x != null) {
|
|
x; // T & {}
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
}
|
|
|
|
function f22<T extends {} | undefined>(x: T) {
|
|
if (x !== undefined) {
|
|
x; // T & {}
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (x !== null) {
|
|
x; // T
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (x !== undefined && x !== null) {
|
|
x; // T & {}
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (x != undefined) {
|
|
x; // T & {}
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
if (x != null) {
|
|
x; // T & {}
|
|
}
|
|
else {
|
|
x; // T
|
|
}
|
|
}
|
|
|
|
function f23<T>(x: T | undefined | null) {
|
|
if (x !== undefined) {
|
|
x; // T & {} | null
|
|
}
|
|
if (x !== null) {
|
|
x; // T & {} | undefined
|
|
}
|
|
if (x != undefined) {
|
|
x; // T & {}
|
|
}
|
|
if (x != null) {
|
|
x; // T & {}
|
|
}
|
|
}
|
|
|
|
function f30(x: {}) {
|
|
if (typeof x === "object") {
|
|
x; // object
|
|
}
|
|
}
|
|
|
|
function f31<T>(x: T) {
|
|
if (typeof x === "object") {
|
|
x; // T & object | T & null
|
|
}
|
|
if (x && typeof x === "object") {
|
|
x; // T & object
|
|
}
|
|
if (typeof x === "object" && x) {
|
|
x; // T & object
|
|
}
|
|
}
|
|
|
|
function f32<T extends {} | undefined>(x: T) {
|
|
if (typeof x === "object") {
|
|
x; // T & object
|
|
}
|
|
}
|
|
|
|
function possiblyNull<T>(x: T) {
|
|
return !!true ? x : null; // T | null
|
|
}
|
|
|
|
function possiblyUndefined<T>(x: T) {
|
|
return !!true ? x : undefined; // T | undefined
|
|
}
|
|
|
|
function possiblyNullOrUndefined<T>(x: T) {
|
|
return possiblyUndefined(possiblyNull(x)); // T | null | undefined
|
|
}
|
|
|
|
function ensureNotNull<T>(x: T) {
|
|
if (x === null) throw Error();
|
|
return x; // T & ({} | undefined)
|
|
}
|
|
|
|
function ensureNotUndefined<T>(x: T) {
|
|
if (x === undefined) throw Error();
|
|
return x; // T & ({} | null)
|
|
}
|
|
|
|
function ensureNotNullOrUndefined<T>(x: T) {
|
|
return ensureNotUndefined(ensureNotNull(x)); // T & {}
|
|
}
|
|
|
|
function f40(a: string | undefined, b: number | null | undefined) {
|
|
let a1 = ensureNotNullOrUndefined(a); // string
|
|
let b1 = ensureNotNullOrUndefined(b); // number
|
|
}
|
|
|
|
type QQ<T> = NonNullable<NonNullable<NonNullable<T>>>;
|
|
|
|
function f41<T>(a: T) {
|
|
let a1 = ensureNotUndefined(ensureNotNull(a)); // T & {}
|
|
let a2 = ensureNotNull(ensureNotUndefined(a)); // T & {}
|
|
let a3 = ensureNotNull(ensureNotNull(a)); // T & {} | T & undefined
|
|
let a4 = ensureNotUndefined(ensureNotUndefined(a)); // T & {} | T & null
|
|
let a5 = ensureNotNullOrUndefined(ensureNotNullOrUndefined(a)); // T & {}
|
|
let a6 = ensureNotNull(possiblyNullOrUndefined(a)); // T & {} | undefined
|
|
let a7 = ensureNotUndefined(possiblyNullOrUndefined(a)); // T & {} | null
|
|
let a8 = ensureNotNull(possiblyUndefined(a)); // T & {} | undefined
|
|
let a9 = ensureNotUndefined(possiblyNull(a)); // T & {} | null
|
|
}
|
|
|
|
// Repro from #48468
|
|
|
|
function deepEquals<T>(a: T, b: T): boolean {
|
|
if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) {
|
|
return false;
|
|
}
|
|
if (Array.isArray(a) || Array.isArray(b)) {
|
|
return false;
|
|
}
|
|
if (Object.keys(a).length !== Object.keys(b).length) { // Error here
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Repro from #49386
|
|
|
|
function foo<T>(x: T | null) {
|
|
let y = x;
|
|
if (y !== null) {
|
|
y;
|
|
}
|
|
}
|
|
|
|
// We allow an unconstrained object of a generic type `T` to be indexed by a key of type `keyof T`
|
|
// without a check that the object is non-undefined and non-null. This is safe because `keyof T`
|
|
// is `never` (meaning no possible keys) for any `T` that includes `undefined` or `null`.
|
|
|
|
function ff1<T>(t: T, k: keyof T) {
|
|
t[k];
|
|
}
|
|
|
|
function ff2<T>(t: T & {}, k: keyof T) {
|
|
t[k];
|
|
}
|
|
|
|
function ff3<T>(t: T, k: keyof (T & {})) {
|
|
t[k]; // Error
|
|
}
|
|
|
|
function ff4<T>(t: T & {}, k: keyof (T & {})) {
|
|
t[k];
|
|
}
|
|
|
|
ff1(null, 'foo'); // Error
|
|
ff2(null, 'foo'); // Error
|
|
ff3(null, 'foo');
|
|
ff4(null, 'foo'); // Error
|
|
|
|
// Repro from #49681
|
|
|
|
type Foo = { [key: string]: unknown };
|
|
type NullableFoo = Foo | undefined;
|
|
|
|
type Bar<T extends NullableFoo> = NonNullable<T>[string];
|
|
|
|
// Generics and intersections with {}
|
|
|
|
function fx0<T>(value: T & ({} | null)) {
|
|
if (value === 42) {
|
|
value; // T & {}
|
|
}
|
|
else {
|
|
value; // T & ({} | null)
|
|
}
|
|
}
|
|
|
|
function fx1<T extends unknown>(value: T & ({} | null)) {
|
|
if (value === 42) {
|
|
value; // T & {}
|
|
}
|
|
else {
|
|
value; // T & ({} | null)
|
|
}
|
|
}
|
|
|
|
function fx2<T extends {}>(value: T & ({} | null)) {
|
|
if (value === 42) {
|
|
value; // T & {}
|
|
}
|
|
else {
|
|
value; // T & ({} | null)
|
|
}
|
|
}
|
|
|
|
function fx3<T extends {} | undefined>(value: T & ({} | null)) {
|
|
if (value === 42) {
|
|
value; // T & {}
|
|
}
|
|
else {
|
|
value; // T & ({} | null)
|
|
}
|
|
}
|
|
|
|
function fx4<T extends {} | null>(value: T & ({} | null)) {
|
|
if (value === 42) {
|
|
value; // T & {}
|
|
}
|
|
else {
|
|
value; // T & ({} | null)
|
|
}
|
|
}
|
|
|
|
function fx5<T extends {} | null | undefined>(value: T & ({} | null)) {
|
|
if (value === 42) {
|
|
value; // T & {}
|
|
}
|
|
else {
|
|
value; // T & ({} | null)
|
|
}
|
|
}
|
|
|
|
// Double-equals narrowing
|
|
|
|
function fx10(x: string | number, y: number) {
|
|
if (x == y) {
|
|
x; // string | number
|
|
}
|
|
else {
|
|
x; // string | number
|
|
}
|
|
if (x != y) {
|
|
x; // string | number
|
|
}
|
|
else {
|
|
x; // string | number
|
|
}
|
|
}
|
|
|
|
// Repros from #50706
|
|
|
|
function SendBlob(encoding: unknown) {
|
|
if (encoding !== undefined && encoding !== 'utf8') {
|
|
throw new Error('encoding');
|
|
}
|
|
encoding;
|
|
};
|
|
|
|
function doSomething1<T extends unknown>(value: T): T {
|
|
if (value === undefined) {
|
|
return value;
|
|
}
|
|
if (value === 42) {
|
|
throw Error('Meaning of life value');
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function doSomething2(value: unknown): void {
|
|
if (value === undefined) {
|
|
return;
|
|
}
|
|
if (value === 42) {
|
|
value;
|
|
}
|
|
}
|
|
|
|
// Repro from #51009
|
|
|
|
type TypeA = {
|
|
A: 'A',
|
|
B: 'B',
|
|
}
|
|
|
|
type TypeB = {
|
|
A: 'A',
|
|
B: 'B',
|
|
C: 'C',
|
|
}
|
|
|
|
type R<T extends keyof TypeA> =
|
|
T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never;
|
|
|
|
type R2<T extends PropertyKey> =
|
|
T extends keyof TypeA ? T extends keyof TypeB ? [TypeA[T], TypeB[T]] : never : never;
|
|
|
|
// Repro from #51041
|
|
|
|
type AB = "A" | "B";
|
|
|
|
function x<T_AB extends AB>(x: T_AB & undefined, y: any) {
|
|
let r2: never = y as T_AB & undefined;
|
|
}
|
|
|
|
// Repro from #51538
|
|
|
|
type Left = 'left';
|
|
type Right = 'right' & { right: 'right' };
|
|
type Either = Left | Right;
|
|
|
|
function assertNever(v: never): never {
|
|
throw new Error('never');
|
|
}
|
|
|
|
function fx20(value: Either) {
|
|
if (value === 'left') {
|
|
const foo: 'left' = value;
|
|
}
|
|
else if (value === 'right') {
|
|
const bar: 'right' = value;
|
|
}
|
|
else {
|
|
assertNever(value);
|
|
}
|
|
}
|