インターフェース (interface) とは何ですか?#
// 1、 オブジェクト構造の定義
interface Car {
brand: string;
speed: number;
drive(): void;
}
let myCar: Car = {
brand: "トヨタ",
speed: 120,
drive() {
console.log("速度で運転中: " + this.speed);
}
};
// 2、インターフェースの読み取り専用およびオプションの指定
interface Point {
readonly x: number; // 読み取り専用
readonly y: number; // 読み取り専用
z?: number; // オプション
}
let p1: Point = { x: 10, y: 20 };
type と interface の違いは何ですか?#
unknown と any の違いは何ですか?#
let value: unknown;
value = 42;
// `toFixed` メソッドを呼び出す前に型チェックが必要
if (typeof value === "number") {
value.toFixed(); // 正しい
}
value = "こんにちは";
// `toUpperCase` メソッドを呼び出す前に型チェックが必要
if (typeof value === "string") {
value.toUpperCase(); // 正しい
}
never 型の使い方について説明してください。#
// 例外を投げる
function throwError(message: string): never {
throw new Error(message);
}
// 無限ループ
function infiniteLoop(): never {
while (true) {
// 無限ループ、決して戻らない
}
}
// 網羅的チェック
type Shape = 'circle' | 'square';
function getArea(shape: Shape): number {
switch (shape) {
case 'circle':
return Math.PI * 1 ** 2;
case 'square':
return 1 * 1;
default:
const _exhaustiveCheck: never = shape; // ここでの `shape` は他の値にはならない
throw new Error(`予期しない形状: ${shape}`);
}
}
never と void の違いは何ですか?#
function logMessage(message: string): void {
console.log(message); // この関数は `undefined` を返します
}
function throwError(message: string): never {
throw new Error(message); // この関数は決して戻りません
}
ユニオン型、交差型、型エイリアス、型ガードについて説明してください。#
ユニオン型 (Union Types)#
- ユニオン型 は、変数が複数の型のいずれかであることを許可します。|(パイプ)記号を使用して定義します。
- シーン: ある値が複数の異なる型のいずれかであることを表すために使用されます。たとえば、関数の引数が複数の型のデータを受け入れることができます。
let value: string | number;
function formatInput(input: string | number): string {
if (typeof input === "string") {
return input.toUpperCase();
} else {
return input.toFixed(2);
}
}
交差型 (Intersection Types)#
- 交差型 は、複数の型を 1 つの型に結合し、その型がすべての型の特性を持つことを示します。&(アンパサンド)を使用して定義します。
- シーン: 複数の型のプロパティを組み合わせて、すべてのプロパティを持つオブジェクト型を作成するために使用されます。
interface Person {
name: string;
}
interface Employee {
id: number;
}
let employee: Person & Employee = {
name: "アリス",
id: 123
};
function printEmployee(employee: Person & Employee) {
console.log(`名前: ${employee.name}, ID: ${employee.id}`);
}
型エイリアス (Type Aliases)#
- 型エイリアス は、型に新しい名前(エイリアス)を作成するために使用されます。type キーワードを使用して定義し、基本型、ユニオン型、交差型などに適用されます。
- シーン: 複雑な型を簡略化し、コードの可読性を向上させるために使用されます。オブジェクト、関数、ユニオン型などの複雑な型に対して簡単なエイリアスを作成できます。
type ID = string | number;
let userId: ID = "abc123";
type User = {
name: string;
age: number;
};
function greet(user: User) {
console.log(`こんにちは、${user.name}`);
}
型ガード (Type Guards)#
型ガード は、ts で特定の値の実際の型を判断し、その型に基づいてさらに処理を行う技術です。ユニオン型を使用する際に非常に便利で、異なる型の分岐で適切な操作を正しく実行できるようにします。
- typeof 型ガード: 基本型(string, number, boolean など)を判断するために使用されます。
function printId(id: string | number) {
if (typeof id === "string") {
console.log(id.toUpperCase());
} else {
console.log(id.toFixed(2));
}
}
- instanceof 型ガード: オブジェクトが特定のクラスのインスタンスであるかどうかを判断するために使用されます。
class Dog {
bark() {
console.log("ワン!");
}
}
class Cat {
meow() {
console.log("ニャー!");
}
}
function makeSound(animal: Dog | Cat) {
if (animal instanceof Dog) {
animal.bark();
} else {
animal.meow();
}
}
- is キーワード: 関数の戻り値として is を使用してカスタム型ガードを作成できます。
function isString(value: any): value is string {
return typeof value === "string";
}
function printValue(value: string | number) {
if (isString(value)) {
console.log(value.toUpperCase());
} else {
console.log(value.toFixed(2));
}
}
- in キーワード: オブジェクトが特定のプロパティを持っているかどうかを判断するために使用され、特にユニオン型内のオブジェクト型を判断する際に便利です。
interface Bird {
fly(): void;
}
interface Fish {
swim(): void;
}
function move(animal: Bird | Fish) {
if ("fly" in animal) {
animal.fly();
} else {
animal.swim();
}
}
typeof キーワードの役割は何ですか?#
// 1、既存の変数の型を再利用
let person = {
name: "アリス",
age: 25,
};
type PersonType = typeof person; // { name: string; age: number; }
// 2、関数の戻り値の型
function getPerson() {
return { name: "アリス", age: 25 };
}
type PersonType = typeof getPerson(); // { name: string; age: number; }
// 3、JavaScript における型チェック
function printValue(value: number | string) {
if (typeof value === "string") {
console.log("これは文字列です: ", value);
} else {
console.log("これは数値です: ", value);
}
}
keyof キーワードの役割は何ですか?#
// 1、オブジェクト型のキーを取得
type Person = {
name: string;
age: number;
location: string;
};
type PersonKeys = keyof Person; // 'name' | 'age' | 'location'
// 2、型制約(keyはobjのオブジェクトキーでなければならない)
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const person = { name: "アリス", age: 25, location: "NYC" };
const name = getValue(person, "name");
const age = getValue(person, "age");
列挙型をどのように定義しますか?使用シーンは?#
enum ResultEnum {
SUCCESS = 200,
ERROR = 500,
NOTLOGGED = 401,
OVERDUE = 402,
TIMEOUT = 5000,
}
enum LogLevel {
Info,
Warn,
Error
}
列挙型のキーをどのように結合しますか?#
enum Direction {
Up,
Down,
Left,
Right
}
type DirectionType = keyof typeof Direction; // Up | Down | Left | Right
ジェネリクス (generics) とは何ですか?#
// 簡単なジェネリック関数
function echo<T>(arg: T): T {
return arg;
}
echo<number>(42); // number 型を渡す
// ジェネリックインターフェース
interface Box<T> {
content: T;
}
// デフォルトのジェネリック型
function createArray<T = string>(length: number, value: T): T[] {
return Array(length).fill(value);
}
ジェネリック型に制約をかけるには?#
ジェネリックパラメータが特定の条件を満たす必要があることを規定します。たとえば、特定のプロパティやメソッドを持つ必要があります。
interface Lengthwise {
length: number;
}
function logLength<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
logLength("こんにちは"); // 文字列は length プロパティを持つため、合法
// logLength(123); // ここではエラーが発生します。なぜなら、number 型には length プロパティがないからです。
as の役割は?いつ使用しますか?#
let someValue: any = "これは文字列です";
// someValue が string 型であることを知っている
let strLength: number = (someValue as string).length;
let colors = ["red", "green", "blue"] as const;
// `colors` の型は readonly ["red", "green", "blue"] になります。
タプルとは?ts 配列との違いは?#
let tuple: [string, number];
tuple = ["こんにちは", 42]; // 合法
// tuple = [42, "こんにちは"]; // 非合法、順序が間違っています
function getUserInfo(): [string, number] {
return ["アリス", 25];
}
let entry: [string, number] = ["score", 100];
console.log(entry[0]); // "score" を出力
// オプション要素のタプル
type FlexibleTuple = [string, number?, boolean?];
let tuple1: FlexibleTuple = ["こんにちは"];
関数のオーバーロードとは何ですか?その役割は?#
// オーバーロードシグネチャ(実装なし)
function format(input: number): string;
function format(input: Date): string;
// 実装シグネチャ(ロジックを含む)
function format(input: any): string {
if (typeof input === "number") {
return input.toFixed(2); // 数字をフォーマット
} else if (input instanceof Date) {
return input.toISOString(); // 日付をフォーマット
}
}
// 異なる数、型の引数
function greet(name: string): string;
function greet(firstName: string, lastName: string): string;
function greet(firstName: string, lastName?: string): string {
if (lastName) {
return `こんにちは、${firstName} ${lastName}!`;
} else {
return `こんにちは、${firstName}!`;
}
}
条件型をどのように実装しますか?#
条件型は通常、T extends U ? X : Y の形式で記述され、T extends U は条件判断を示します。条件が真であれば型 X を返し、そうでなければ型 Y を返します。これは、JavaScript の三項演算子 condition ? trueValue : falseValue に似ています。
T extends U ? X : Y
// • T extends U:条件を示し、型 T が型 U に代入可能かどうかをチェックします。
// • X:T が条件を満たす場合(つまり T extends U が true の場合)に返される型。
// • Y:T が条件を満たさない場合(つまり T extends U が false の場合)に返される型。
// 例:
type IsString<T> = T extends string ? "はい" : "いいえ";
type A = IsString<string>; // "はい"
type B = IsString<number>; // "いいえ"
よく使われる組み込みのユーティリティ型は何ですか?#
Partial<T>#
型 T のすべてのプロパティをオプションプロパティに変換します。
const Person = {
name: string;
age: number;
}
type PartialPerson = Partial<Person>;
// PartialPerson は { name?: string; age?: number; } と等価です。
Required<T>#
型 T のすべてのプロパティを必須プロパティに変換します。
interface Person {
name?: string;
age?: number;
}
type RequiredPerson = Required<Person>;
// RequiredPerson は { name: string; age: number; } と等価です。
Readonly<T>#
型 T のすべてのプロパティを読み取り専用プロパティに変換し、変更を許可しません。
interface Person {
name: string;
age: number;
}
type ReadonlyPerson = Readonly<Person>;
// ReadonlyPerson は { readonly name: string; readonly age: number; } と等価です。
Pick<T, K>#
型 T から一部のプロパティを選択して新しい型を構成します。K は選択するプロパティのユニオン型です。
interface Person {
name: string;
age: number;
address: string;
}
type PersonNameAndAge = Pick<Person, "name" | "age">;
// PersonNameAndAge は { name: string; age: number; } と等価です。
Omit<T, K>#
型 T から K で指定されたプロパティを除外し、新しい型を構成します。
interface Person {
name: string;
age: number;
address: string;
}
type PersonWithoutAddress = Omit<Person, "address">;
// PersonWithoutAddress は { name: string; age: number; } と等価です。
Record<K,T>#
型を構成し、キー K は文字列、数字などで、値 T はすべてのプロパティの型です。
type Page = "home" | "about" | "contact";
type PageInfo = { title: string };
const pages: Record<Page, PageInfo> = {
home: { title: "ホームページ" },
about: { title: "私たちについて" },
contact: { title: "お問い合わせ" },
};
Exclude<T,U>#
ユニオン型 T から型 U に属するすべてのサブタイプを除外します。
type A = "a" | "b" | "c";
type B = "a";
type Result = Exclude<A, B>; // "b" | "c"
Extract<T,U>#
ユニオン型 T から型 U に代入可能なすべてのサブタイプを抽出します。
type A = "a" | "b" | "c";
type B = "a" | "b";
type Result = Extract<A, B>; // "a" | "b"
NonNullable<T>#
型 T の null および undefined を除外します。
type A = string | null | undefined;
type NonNullableA = NonNullable<A>; // string
ReturnType<T>#
関数型 T の戻り値の型を取得します。
function getUser() {
return { name: "アリス", age: 25 };
}
type UserType = ReturnType<typeof getUser>;
// UserType は { name: string; age: number; } と等価です。
InstanceType<T>#
コンストラクタ関数型 T のインスタンス型を取得します。
class Person {
name: string = "アリス";
age: number = 25;
}
type PersonInstance = InstanceType<typeof Person>;
// PersonInstance は Person と等価です。
Parameters<T>#
関数型 T の引数の型を取得し、タプル型を返します。
function greet(name: string, age: number): string {
return `こんにちは ${name}、あなたは ${age} 歳です。`;
}
type GreetParams = Parameters<typeof greet>;
// GreetParams は [string, number] と等価です。
ConstructorParameters<T>#
コンストラクタ関数型 T の引数の型を取得し、タプル型を返します。
class Person {
constructor(public name: string, public age: number) {}
}
type PersonConstructorParams = ConstructorParameters<typeof Person>;
// PersonConstructorParams は [string, number] と等価です。
ThisType<T>#
コンテキストオブジェクト this の型を指定するために使用され、通常は noImplicitThis オプションと組み合わせて使用されます。
type ObjectDescriptor<D, M> = {
data?: D;
methods?: M & ThisType<D & M>; // M の this は D & M 型として推論されます
};
let obj: ObjectDescriptor<{ x: number }, { foo(): void }> = {
data: { x: 10 },
methods: {
foo() {
console.log(this.x); // number として推論されます
}
}
};
Awaited<T>#
Promise の解決型を取得します。
type P = Promise<string>;
type Result = Awaited<P>; // string
declare、declare global とは何ですか?#
.d.ts と .ts ファイルの違いは何ですか?#
コンポーネントテンプレートインスタンスの参照に型を注釈するには?#
<template>
<MyComponent ref="myComponentRef" message="こんにちは、世界!" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import MyComponent from './MyComponent.vue';
const myComponentRef = ref<InstanceType<typeof MyComponent> | null>(null)
</script>
typescript.json 設定の説明!#
https://typescript.p6p.net/typescript-tutorial/tsconfig.json.html#compileoptions
{
// コンパイルオプション
"compilerOptions": {
// ECMAScript のターゲットバージョンを指定します(例:ES5、ES6、ESNext)。
"target": "ES6",
// 使用するモジュールシステムを指定します
"module": "ESNext",
// すべての厳格な型チェックオプションを有効にするフラグ。
"strict": true,
// ES モジュールの相互運用性サポートを有効にします。
"esModuleInterop": true,
// デバッグ用に .map ファイルを生成します。
"sourceMap": true,
// JSX コードのコンパイル方法を指定します(例:react、react-jsx、preserve)。
"jsx": "preserve",
// 使用するライブラリファイルを指定します(例:DOM、ES6、ESNext)。
"lib": ["ES6", "DOM"],
// 使用するライブラリファイルを指定します(例:DOM、ES6、ESNext)。
"skipLibCheck": true,
// 型注釈がない場合に暗黙の any 型を禁止します。
"noImplicitAny": true,
// 宣言ファイルを生成します。これを有効にすると、自動的に宣言ファイルが生成されます。
"declaration": true,
// 宣言ファイルの生成先ディレクトリを指定します。
"declarationDir": "./file",
// 宣言ファイルのみを生成し、js ファイルは生成しません。
"emitDeclarationOnly": true,
// export= によるエクスポートを許可し、import from でインポートします。
"esModuleInterop": true,
// 非相対モジュールの基準となるディレクトリを解決します。デフォルトは現在のディレクトリです。
"baseUrl": "./",
// パスのマッピング。baseUrl に対して相対的です。
"paths": {
"@/*": ["./src/*"]
},
// ...
},
// 含まれるファイルまたはディレクトリ
"include": [],
// 除外されるファイルまたはディレクトリ
"exclude": [],
// コンパイルする具体的なファイルリストを指定します。小規模プロジェクトに適しています。
"files": [],
// プロジェクト間の参照をサポートするために使用され、大規模プロジェクトに適しています。
"references": [],
// 他の設定を継承します
"extends": ""
}