カテゴリー
個人的Typescriptの型入門② 〜 オブジェクト型の応用
※ 当ページには【広告/PR】を含む場合があります。
2024/09/09
目次
- 1. オブジェクト型〜応用編
- 1-1. 「?」プロパティ修飾子
- 1-2. オプショナルなプロパティへのアクセス
- 1-3. 極力「?」修飾子に頼らない
- 1-4. 「exactOptionalPropertyTypes」コンパイラオプション
- 1-5. 「readonly」プロパティ修飾子
- 1-6. readonlyの注意点
- 1-7. インデックスシグネチャ
- 1-8. インデックスシグネチャの注意点
- 1-9. 関数シグネチャ
- 1-10. 複数の関数シグネチャによるオーバーローディング
- 1-11. newシグネチャ
- 1-12. asによるダウンキャスト
- 1-13. asの注意点
- 1-14. readonlyな配列型
- 1-15. readonlyなタプル型
- 1-16. Variadic Tuple Types
- 1-17. Variadic Tuple Typesの応用
- 1-18. 「[...T]」と「T」の違い
- 1-19. テンプレートリテラル型
- 1-20. テンプレートリテラルの利用法
- 1-21. as const
- 1-22. as constの使いどころ
- 1-23. as constとテンプレート文字列リテラル
- 2. まとめ
オブジェクト型〜応用編
「?」プロパティ修飾子
interface MyObj {
foo: string;
bar?: number;
}
let obj: MyObj = { foo: 'string' };
obj = { foo: 'foo', bar: 100 };
オプショナルなプロパティへのアクセス
undefined
number | undefined
?
interface MyObj {
foo: string;
bar?: number;
}
function func(obj: MyObj): number {
return obj.bar !== undefined ? obj.bar * 100 : 0;
}
極力「?」修飾子に頼らない
?
number | undefined
?
interface MyObj1 {
foo: string;
bar?: number;
}
interface MyObj2 {
foo: string;
bar: number | undefined;
}
//オプショナルなプロパティはなくてもエラーは出ない
let obj: MyObj1 = {
foo: 'string',
};
//✘ Type '{ foo: string; }' is not assignable to type 'MyObj'.
// Property 'bar' is missing in type '{ foo: string; }'.
let obj: MyObj2 = {
foo: 'string',
};
「exactOptionalPropertyTypes」コンパイラオプション
exactOptionalPropertyTypes
undefined
interface MyObj {
foo: string;
bar?: number;
}
//exactOptionalPropertyTypesが無効の場合、以下は全部OK
const obj1: MyObj = { foo: "pichu" };
const obj2: MyObj = { foo: "pikachu", bar: 25 };
const obj3: MyObj = { foo: "raichu", bar: undefined };
undefined
interface MyObj {
foo: string;
bar?: number;
}
//exactOptionalPropertyTypesが有効の場合:
//✘ Type 'undefined' is not assignable to type 'number'.
const obj3: MyObj = { foo: "raichu", bar: undefined };
bar?: number;
bar?: number;
//exactOptionalPropertyTypesが有効の状態
interface MyObj {
foo: string;
bar?: number;
}
function func(obj: MyObj) {
if ("bar" in obj) {
//obj.barはnumber型
console.log(obj.bar.toFixed(1));
}
}
exactOptionalPropertyTypes
「readonly」プロパティ修飾子
interface MyObj {
readonly foo: string;
}
const obj: MyObj = {
foo: 'Hey!',
};
//✘ Cannot assign to 'foo' because it is a constant or a read-only property.
obj.foo = 'Hi';
readonlyの注意点
interface MyObj {
readonly foo: string;
}
interface MyObj2 {
foo: string;
}
const obj: MyObj = { foo: 'Hey!', }
const obj2: MyObj2 = obj;
obj2.foo = 'Hi';
console.log(obj.foo); // 'Hi'
インデックスシグネチャ
interface MyObj {
[key: string]: number;
}
const obj: MyObj = {};
const num: number = obj.foo;
const num2: number = obj.bar;
[key: string]: number;
インデックスシグネチャの注意点
interface Array<T> {
[idx: number]: T;
length: number;
// メソッドの定義が続く
// ...
}
関数シグネチャ
interface Func {
(arg: number): void;
}
const f: Func = (arg: number) => { console.log(arg); };
(arg: number): void;
複数の関数シグネチャによるオーバーローディング
interface Func {
foo: string;
(arg: number): void;
(arg: string): string;
}
newシグネチャ
interface Ctor<T> {
new(): T;
}
class Foo {
public bar: number | undefined;
}
const f: Ctor<Foo> = Foo;
const obj = new f();
Ctor<T>
new
Ctor<Foo>
(foo: string)=>number
new()=>Foo
asによるダウンキャスト
評価式 as 型
function rand(): string | number {
if (Math.random() < 0.5) {
return 'hello';
} else {
return 123;
}
}
const value = rand();
const str = value as number;
console.log(str * 10);
string | number
value as number
asの注意点
const value = 'foo';
//✘ Type 'string' cannot be converted to type 'number'.
const str = value as number;
const value = 'foo';
const str = value as unknown as number;
//const foo: string = 'foo'; と同じ結果になる
const foo = 'foo' as string;
readonlyな配列型
const arr: readonly number[] = [1, 2, 3];
//✘ Index signature in type 'readonly number[]' only permits reading.
arr[0] = 100;
//✘ Property 'push' does not exist on type 'readonly number[]'
arr.push(4);
readonly T[]
T[]
Array<T>
readonly T[]
ReadonlyArray<T>
readonly Array<T>
readonlyなタプル型
const tuple: readonly [string, number] = ['foo', 123];
//✘ Cannot assign to '0' because it is a read-only property.
tuple[0] = 'bar';
readonly [string, number]
Variadic Tuple Types
type SNS = [string, number, string];
//[string, string, number, string, number]型
type SSNSN = [string, ...SNS, number];
Variadic Tuple Typesの応用
...T
function removeFirst<T, Rest extends readonly unknown[]>(
arr: [T, ...Rest]
): Rest {
const [, ...rest] = arr;
return rest;
}
//arrは[number, number, string]型
const arr = removeFirst([1, 2, 3, "foo"]);
[number, number, string]
[1, 2, 3, "foo"]
[T, ...Rest]
...T
T
Rest extends readonly unknown[]
「[...T]」と「T」の違い
[...T]
[...T]
T
function func1<T extends readonly unknown[]>(arr: T): T {
return arr;
}
function func2<T extends readonly unknown[]>(arr: [...T]): T {
return arr;
}
//arr1はnumber[]型
const arr1 = func1([1, 2, 3]);
//arr2は[number, number, number]型
const arr2 = func2([1, 2, 3]);
T
[...T]
テンプレートリテラル型
type HelloStr = `Hello, ${string}`;
const str1: HelloStr = "Hello, world!";
const str2: HelloStr = "Hello, uhyo";
//✘ Type '"Hell, world!"' is not assignable to type '`Hello, ${string}`'.
const str3: HelloStr = "Hell, world!";
HelloStr
Hello,
Hello,
テンプレートリテラルの利用法
type PriceStr = `${number}円`;
const str1: PriceStr = "100円";
const str2: PriceStr = "-50円";
const str3: PriceStr = "3.14円"
const str4: PriceStr = "1e100円";
// ここから下は全部エラー
const str5: PriceStr = "1_000_000円";
const str6: PriceStr = "円";
const str7: PriceStr = "1,234円";
const str8: PriceStr = "NaN円";
const str9: PriceStr = "Infinity円";
${number型}
${string型}
${文字列リテラル型のUnion型}
as const
//fooはstring型
let foo = '123';
'123'
as const
"123"
//foo2は"123"型
let foo2 = '123' as const;
as constの使いどころ
「as const」
const obj = {
foo: "123",
bar: [1, 2, 3]
};
//👇objの型は
// {foo: string; bar: number[]}
const obj2 = {
foo: "123",
bar: [1, 2, 3]
} as const;
//👇obj2は型
// {
// readonly foo: "123";
// readonly bar: readonly [1, 2, 3];
// }
as const
{ foo: string; bar: number[] }
obj.foo = "456";
as const
readonlyタプル型
readonly [1, 2, 3]
as constとテンプレート文字列リテラル
as const
const world: string = "world";
// string型
const str1 = `Hello, ${world}!`;
// `Hello, ${string}!` 型
const str2 = `Hello, ${world}!` as const;
as const
as const
1. 文字列・数値・ブール値リテラルに作用させると、それ自体のリテラル型として推論される
2. テンプレート文字列リテラルに作用させると、テンプレートリテラル型に推論される
3. オブジェクトリテラルに作用させると、各プロパティがreadonlyを持つ
4. 配列リテラルに作用させると、readonlyタプル型になる
まとめ
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー
- 1. オブジェクト型〜応用編
- 1-1. 「?」プロパティ修飾子
- 1-2. オプショナルなプロパティへのアクセス
- 1-3. 極力「?」修飾子に頼らない
- 1-4. 「exactOptionalPropertyTypes」コンパイラオプション
- 1-5. 「readonly」プロパティ修飾子
- 1-6. readonlyの注意点
- 1-7. インデックスシグネチャ
- 1-8. インデックスシグネチャの注意点
- 1-9. 関数シグネチャ
- 1-10. 複数の関数シグネチャによるオーバーローディング
- 1-11. newシグネチャ
- 1-12. asによるダウンキャスト
- 1-13. asの注意点
- 1-14. readonlyな配列型
- 1-15. readonlyなタプル型
- 1-16. Variadic Tuple Types
- 1-17. Variadic Tuple Typesの応用
- 1-18. 「[...T]」と「T」の違い
- 1-19. テンプレートリテラル型
- 1-20. テンプレートリテラルの利用法
- 1-21. as const
- 1-22. as constの使いどころ
- 1-23. as constとテンプレート文字列リテラル
- 2. まとめ