"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit", // import自動ソート
"source.fixAll": "explicit", // eslintやprettierのfixを実行
"source.addMissingImports": "explicit" // import文自動挿入
},
"typescript.preferences.importModuleSpecifier": "non-relative", // import文を絶対パスで自動補完
},
https://www.typescriptlang.org/ja/tsconfig/#include
プログラムに含めるファイル名またはパターンのリストを指定します。 ファイル名はtsconfig.jsonファイルを含んでいるディレクトリからの相対パスとして解決されます。
tsconfig.json
{
"include": ["src/**/*", "tests/**/*"]
}
https://www.typescriptlang.org/ja/tsconfig/#exclude
includeの解決時にスキップさせるファイル名やパターンのリストを指定します。
address?: string;
と
address: string | undefined;
を同じと認識されている方が多いようですが、以下のようにキーが存在するかどうか?という点で違いがあります。
interface Person {
name: string;
age: number;
address?: string;
}
const person1:Person = { name:"yamada", age:20 };
const person2:Person = { name:"yamada", age:20, address: undefined };
console.log(person1.address); // undefined
console.log(person2.address); // undefined
console.log(Object.keys(person1)); // [ 'name', 'age' ]
console.log(Object.keys(person2)); // [ 'name', 'age', 'address' ]
if (variable instanceof Date) {
console.log('変数はDate型です。');
} else {
console.log('変数はDate型ではありません。');
}
if (Object.prototype.toString.call(variable) === '[object Date]') {
console.log('変数はDate型です。');
} else {
console.log('変数はDate型ではありません。');
}
以下のように配列から型を自動的に生成することができます。
このようにしておくことで配列に変更があった時に型の修正の必要がありません。
const STATUS_VALUES = ["productInCart", "productInCheckout", "productPurchased"] as const;
type Status = typeof STATUS_VALUES[number]; // "productInCart" | "productInCheckout" | "productPurchased"
as constアサーション を行うと次のような制約をつけることができます。
1. 「値」や「配列やオブジェクトの全てのメンバ」が readonlyとなる。
2. Widening(型の拡大)がされない
const pikachu = {
name: "pikachu", // readonly
height: 0.4, // readonly
weight: 6.0, // readonly
} as const;
// string型
let hoge = "my-sample-text"
// "my-sample-text"型
let fuga = "my-sample-text" as const
// 関数を定義
function getfirstMember<T>(list: T[]) {
return list[0]
}
この関数に対して、型をアノテートしないで使用した場合は引数から型推論される
type User = {
id: number
age: number
name: string
}
const users: User[] = [
{
id: 1,
age: 22,
name: "太郎",
},
{
id: 2,
age: 41,
name: "花子",
},
]
const resultA = getfirstMember(users) // resultAの型は User
const resultB = getfirstMember(["hoge", "fuga"]) // resultBの型は string
const resultC = getfirstMember([undefined, true, false]) // resultCの型は boolean|undefined
const resultD = getfirstMember(true) // エラー
const result = getfirstMember([() => {}, () => {}]) // resultEの型は () => void
条件型 は 以下のような三項演算子のような記述で型を定義します。(条件式に合致するときはX。それ以外はY。)
type MyType = 条件式 ? X : Y
条件式 にはいろいろな記述があります。 例えば
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
type MyType1 = Dog extends Animal ? number : string;
// これは以下 ↓ と同じです。
type MyType1 = number
type MyType2 = RegExp extends Animal ? number : string;
// これは以下 ↓ と同じです。
type MyType2 = string
Typescript の 型をいい感じで変換できるのが、ユーティリティータイプです。
https://www.typescriptlang.org/docs/handbook/utility-types.html
Pick<Type, Keys>: あるTypeの一部を取り出して新しい型にする
Omit<Type, Keys>: あるTypeの一部を削除して新しい型にする
Partial<Type>: あるTypeの全てのメンバをオプショナルにして新しい型にする
Required<Type>: あるTypeの全てのメンバを必須にして新しい型にする
Parameters<Type>: Type(関数の引数)から型を作成する
ReturnType<Type>: 関数の返り値の型で型を作成
Readonly<Type>: あるTypeReadOnlyな型にする
Record<Keys,Type>: 型を組み合わせてオブジェクトの型を作成
Exclude<Type, ExcludedUnion>: Typeの中から指定したUnion型を取り除いて、新しい型にする
Extract<Type, Union>: Typeの中から指定したUnion型を抜き取って、新しい型にする
export type Memo = {
id: string;
name: string;
content: string;
created_at: string;
updated_at: string;
};
export type MemoRequest = Omit<Memo, 'id' | 'created_at' | 'updated_at'>;
引用 :
TypeScriptのUtility Typesを理解して活用する - Qiita
【TypeScript】覚えておきたいUtility Types
enum StringEnum {
Small = 'S',
Medium = 'M',
Large = 'L',
}
// 👇️ type ValuesUnion = "S" | "M" | "L"
type ValuesUnion = `${StringEnum}`;
// 👇️ type KeysUnion = "Small" | "Medium" | "Large"
type KeysUnion = keyof typeof StringEnum;
const getKeyFromValue = (
enumObj: {},
value: string | number,
): string | undefined =>
(Object.entries(enumObj).find(
(e) => isNaN(Number(e[0])) && e[1] === value,
) ?? [undefined])[0];
const getEnumFromValue = <T extends Record<string, string | number>>(
enumObj: T,
value: string | number,
) => {
const key: keyof T | undefined = getKeyFromValue(enumObj, value);
if (!key) return null;
return enumObj[key] || null;
};
enum DayWeek2{
SAN="日曜日",
MON="月曜日",
TUE="火曜日",
WEN="水曜日",
THU="木曜日",
FRI="金曜日",
SAT="土曜日",
}
type Maybe<T> = T | null;
const check_1:DayWeek2 = DayWeek2.SAT; // ✅ 宣言OK
const check_2:DayWeek2 = DayWeek2['SAT']; // ✅ 宣言OK
const check_3:DayWeek2 = "土曜日"; // ❌ 宣言NG
const check_:Maybe<DayWeek2> = getEnumFromValue(DayWeek2,"土曜日"); // ✅ 宣言OK
const check_4a:Maybe<DayWeek2> = getEnumFromValue(DayWeek2, "土曜日"); // ✅ 宣言OK
console.log( check_4a ); // 土曜日
const check_4b:Maybe<DayWeek2> = getEnumFromValue(DayWeek2, "土曜日hoge"); // ✅ 宣言OK
console.log( check_4b ); // null
const currencies = ["CNY", "EUR", "GBP", "JPY", "KRW", "USD"] as const;
type Currency = typeof currencies[number]; // type Currency = "CNY" | "EUR" | "GBP" | "JPY" | "KRW" | "USD"
こちらにとても上手な説明があります https://qiita.com/yamashin0616/items/f6f2405dba4570638228
(引用させていただきました。 ↑ )
// 例1 : constでLiteral Typesの型を宣言(Widening発生)
const foo: "foo" = "foo"; // Literal Typesの型を宣言
let bar = foo; // 変数fooを変数barに代入
bar = "bar"; // WideningによりErrorにならない
// 例2 : letでLiteral Typesの型を宣言(Wideningが発生しない)
let foo: "foo" = "foo"; // Literal Typesの型を宣言
let bar = foo; // 変数fooを変数barに代入
bar = "bar"; // 変数barの値は"foo"で固定されているため、Errorになる
// 例3 : as constでLiteral Typesの型を宣言(Wideningが発生しない)
const foo = "foo" as const; // as constで変数fooのLiteral Typesの型を宣言
let bar = foo; // 変数fooを変数barに代入
bar = "bar"; // 変数barの値は"foo"で固定されているため、Errorになる
一度定義した後の再代入を禁止する
例
const hoge1:number = 123;
hoge1 = 999; // エラー
オブジェクト型のプロパティにreadonly修飾子をつけることで使用できる。つまりプロパティ以外には使用できない。
ただオブジェクト自体を再代入して書き換えることはできる
例
type User = {
readonly id: number;
readonly name: string;
};
let user01:User = {
id: 1,
name:"Taro Yamada",
}
// エラー:読み取り専用プロパティであるため、'id' に代入することはできません。
user01.id = 2;
// OK
user01 = {
id: 999,
name:"Taro Nise",
}
TypeScript でコールバック関数の型定義をしたい場合は、call signature を付けた interface として定義すれば良い。関数もオブジェクトの一種だから。
interface callbackType{(argv :number) :void};
function func(callback:callbackType){
...
}
OR
指定した型のどれかにマッチすれば良い。
type DrinkOrFood = Drink | Food;
AND
指定した型の全てにマッチすれば良い。
type Drink AndFood = Drink & Food;
interface Drink AndFood extends Drink, Food {}
型ガード(例: data に x というプロパティがあるかどうか?)
if ('x' in data) {
}
interface MyData {
id: number;
name: string;
}
const myData: MyData=
{
id: 1,
name: 'hoge',
}
Object.keys(myData).map((key) => {
console.log(myData[key]); // ★ ここでエラー(TS7053)となります。
});
TS Playground
https://bit.ly/3KxxBgx
このようなエラーが表示されます
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'MyData'.
No index signature with a parameter of type 'string' was found on type 'MyData'.(7053)
Object.keys(myData).map((key) => {
console.log(myData[key]); // ★ ここでエラー(TS7053)となります。
});
↓ 次のように修正します
(Object.keys(myData) as (keyof MyData)[]).map((key) => {
console.log(myData[key]);
});
Object.entries(myData).map(([key, value]) => {
console.log( '● key, value' );
console.log( `${key} : ${value}` );
})
https://stackoverflow.com/questions/59545011/object-with-generic-keys-in-typescript
MyInterface の メンバ名であることを保証する関数を作成します。
name , address, email は適宜書き換えること
function isProperty(value: string): value is (keyof MyInterface){
return value === 'name' || value === 'address' || value === 'email';
}