TypeScriptのTypeGuard
use typeof
code:example.ts
code:TypeScript
function func(value: string | number): number {
if ('string' === typeof value) {
// value: string
return value.length;
} else {
// value: number
return value;
}
}
code:ts
export interface Success {
type: ${string}Success;
body: string;
}
export interface Error {
type: ${string}Error;
message: string;
}
export function handler(r: Success | Error) {
if (r.type === "HttpSuccess") {
// 'r' has type 'Success'
let token = r.body;
return;
}
const a = r; // ここは Success | Errorであることに注意
}
ifの後で、Errorに絞り込まれていないことに注意
なぜなら、HttpSucccess以外のSuccessが存在しうるから
e.g. "HogeSuccess"
const
readonly
instanceof
union
#hoge in obj
code:ts
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; sideLength: number };
function area(shape: Shape): number {
const { kind } = shape;
if (kind === 'circle') {
return Math.PI * shape.radius ** 2;
}
return shape.sideLength ** 2;
}
伝搬できる
code:ts
function f(x: string | number | boolean) {
const isString = typeof x === 'string';
const isNumber = typeof x === 'number';
const isStringOrNumber = isString || isNumber;
if (isStringOrNumber) {
x; // 'string | number'.
} else {
x; // 'x' is 'boolean'.
}
}
分割代入後も判定できる
code:ts
type Action =
| { kind: "NumberContents", payload: number }
| { kind: "StringContents", payload: string };
function processAction(action: Action) {
const { kind, payload } = action;
if (kind === "NumberContents") {
let num = payload * 2
// ...
}
else if (kind === "StringContents") {
const str = payload.trim();
// ...
}
}
ただし、以下のように書いた場合は判定されない
code:ng.ts
const kind = action.kind
const payload = action.payload
code:ng.ts
const {kind} = action
const {payload} = action
上の例でのpayload部分は、property名が共通している必要がある
union型の絞り込み
code:ts
interface Hoge {
foo: string;
bar: number;
}
interface Piyo {
foo: number;
baz: boolean;
}
function useHogePiyo(obj: Hoge | Piyo): void {
// ここではobjはHoge | Piyo型
if ('bar' in obj) { // hasOwnPropertyを使わずともinを使える
// barプロパティがあるのはHoge型なのでここではobjはHoge型
console.log('Hoge', obj.bar);
} else {
// barプロパティがないのでここではobjはPiyo型
console.log('Piyo', obj.baz);
}
}
可変長引数...argsでも使える
code:ts
const f1: Func = (kind, payload) => {
if (kind === "a") {
// 以前 payload :: number | string
// v4.6 payload :: number
}
if (kind === "b") {
// 以前 payload :: number | string
// v4.6 payload :: string
}
};
instanceに対して、それが何のClassのinstanceかを判断できる
code:ts
if (hoge instanceof Hoge) {
hoge; // 'Hoge' 型として扱われる
}
4.7
keyが変数で、obj[key]とした時にもtype guradされるようになった
code:ts
const key = 'a'
const numberOrString = Math.random() < 0.5 ? 42 : "hello";
const obj = {
'a': numberOrString,
};
if (typeof objkey === "string") { // 以前: objkey :: string | number // v4.7: objkey :: string }
// 以前は変数に束縛しておく必要があった
if (typeof a === "string") {
// 以前,v4.7: a :: string
}