This repository has been archived by the owner on Sep 14, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
/
is.ts
108 lines (94 loc) · 2.89 KB
/
is.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import { getOrInit } from "../util/state.ts"
export interface Guard<T, Y extends T> {
(value: T): value is Y
}
export function is(guard: undefined): Guard<unknown, undefined>
export function is(guard: null): Guard<unknown, null>
export function is(guard: typeof Number): Guard<unknown, number>
export function is(guard: typeof String): Guard<unknown, string>
export function is(guard: typeof Boolean): Guard<unknown, boolean>
export function is(guard: typeof BigInt): Guard<unknown, bigint>
export function is(guard: typeof Symbol): Guard<unknown, symbol>
export function is(guard: true): Guard<unknown, true>
export function is(guard: false): Guard<unknown, false>
export function is<T>(guard: abstract new(...args: any) => T): Guard<unknown, T>
export function is<
T extends string | { type: string },
U extends T extends { type: string } ? T["type"] : T,
>(
guard: U,
): Guard<T, Extract<T, U | { type: U }>>
export function is(guard: any): Guard<unknown, any> {
switch (guard) {
case undefined:
return isUndefined
case null:
return isNull
case Number:
return isNumber
case String:
return isString
case Boolean:
return isBoolean
case BigInt:
return isBigInt
case Symbol:
return isSymbol
default:
if (typeof guard === "string") {
return isType(guard)
} else if (typeof guard === "boolean") {
return guard ? isTrue : isFalse
}
{
return isInstance(guard)
}
}
}
function isUndefined(x: unknown): x is undefined {
return typeof x === "undefined"
}
function isNull(x: unknown): x is null {
return x === null
}
function isNumber(x: unknown): x is number {
return typeof x === "number"
}
function isString(x: unknown): x is string {
return typeof x === "string"
}
function isBoolean(x: unknown): x is boolean {
return typeof x === "boolean"
}
function isBigInt(x: unknown): x is bigint {
return typeof x === "bigint"
}
function isSymbol(x: unknown): x is symbol {
return typeof x === "symbol"
}
function isTrue(x: unknown): x is true {
return x === true
}
function isFalse(x: unknown): x is false {
return x === false
}
function isType<
T extends string | { type: string },
U extends T extends { type: string } ? T["type"] : T,
>(type: U) {
return (value: T): value is Extract<T, U | { type: U }> =>
(value as any) === type || (value as any).type === type
}
const isInstanceMemo = new WeakMap<abstract new(...args: any) => any, Guard<unknown, any>>()
function isInstance<T>(ctor: abstract new(...args: any) => T): Guard<unknown, T> {
return getOrInit(
isInstanceMemo,
ctor,
() => (value: unknown): value is T => value instanceof ctor,
)
}
// Exclude<unknown, null> === unknown
// SmartExclude<unknown, null> === {} | undefined
export type SmartExclude<T1, T2 extends T1> = T2 extends null | undefined
? T1 & Exclude<{} | null | undefined, T2>
: Exclude<T1, T2>