-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample1.ts
More file actions
130 lines (117 loc) · 3.43 KB
/
example1.ts
File metadata and controls
130 lines (117 loc) · 3.43 KB
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import type { ValidatorOf } from "..";
import { like, validate, is, unstable } from "..";
// 適当な型を定義
type SomeTypeA = {
keyA?: string;
keyB: boolean;
keyC: 200;
keyD: {
keyA?: string;
keyB: [number, string];
keyC: (string | boolean)[];
keyD: {
keyA: string;
keyB?: number;
};
};
keyE?: {
keyA: number;
};
keyF?: SomeTypeB;
funA: (a: number) => string;
funB: (a: boolean | null, b: string) => object;
};
// 型の入れ子に使う型
type SomeTypeB = {
keyA: string;
};
// SomeTypeB のバリデータ
// 関数として書ける
const isSomeTypeB: ValidatorOf<SomeTypeB> = (
arg: unknown,
): arg is SomeTypeB => {
const pass =
typeof arg === "object" &&
arg !== null &&
"keyA" in arg &&
is.string(arg.keyA);
return pass;
};
// SomeTypeA のバリデータ
// 基本的なバリデータを組み合わせてオブジェクトとしても書ける
const isSomeTypeA: ValidatorOf<SomeTypeA> = {
// union type の validator は unorderd tuple
// ValidatorOf<string | undefined>
// => [ValidatorOf<string>, ValidatorOf<undefined>]
keyA: [is.string, is.undefined],
keyB: is.boolean,
// as const みたいなのは is.constant 使うとよい
keyC: is.constant(200),
// オブジェクトの入れ子もできる
keyD: {
keyA: [is.string, is.undefined],
// tuple の validator は { type: "tuple", elem: [ValidatorOf<Element1>, ValidatorOf<Element2>, ...] }
keyB: {
type: "tuple",
elem: [is.number, is.string],
},
// array の validator は { type: "array", elem: ValidatorOf<Element> }
keyC: {
type: "array",
elem: [is.string, is.boolean],
},
keyD: {
keyA: is.string,
keyB: [is.undefined, is.number],
},
},
keyE: [is.undefined, { keyA: is.number }],
// 他で定義したバリデータも置くことができる
keyF: [isSomeTypeB, is.undefined],
// メソッド (部分的なサポート) 単に "function" と書く
// 実際には Response#json など単なるデータの any を考えているのでおまけ程度
funA: "function",
// とりあえず成功するバリデータも書ける
funB: is.anyway,
};
// unstable.is.function で引数の数についてのバリデーションを書くこともできる
// 引数や戻り値に関してはランタイムで情報を取れない
isSomeTypeA.funB = unstable.is.function(2);
// バリデーションする値
const possiblySomeTypeA: any = {
keyB: true,
keyC: 200,
keyD: {
keyA: "nested",
keyB: [1, "nested"],
keyC: [true, false, false],
keyD: {
keyA: "double nested",
},
},
funA: (a: number) => "string",
funB: (a: boolean | null, b: string) => {},
};
// バリデーションする
const result = like<SomeTypeA>(possiblySomeTypeA, isSomeTypeA);
console.log(result);
// T/F によって型のナローイングが効く
if (result) {
possiblySomeTypeA; // SomeTypeA
} else {
possiblySomeTypeA; // any
}
() => {
// あとで catch する前提なら平坦にも書ける
const obj = {} as any;
const res = validate<SomeTypeA>(isSomeTypeA)(obj); // throws ValidationError
res; // プログラム上では SomeTypeA
};
async () => {
// fetch とかの Promise に挟みこんで使うと型が付く
// 失敗するなら Promise#catch するとよい
const res = await fetch("")
.then((res) => res.json())
.then(validate<SomeTypeA>(isSomeTypeA));
res; // SomeTypeA
};