banner
小凯同学 xkfe

小凯同学 xkfe

学而不思则罔,思而不学则殆
twitter
github
email

TypeScriptの高頻度面接問題/書き方

インターフェース (interface) とは何ですか?#

// 1、 オブジェクト構造の定義
interface Car {
  brand: string;
  speed: number;
  drive(): void;
}
let myCar: Car = {
  brand: "Toyota",
  speed: 120,
  drive() {
    console.log("Driving at speed: " + 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 = "Hello";
// `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(`Unexpected shape: ${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: "Alice",
  id: 123
};

function printEmployee(employee: Person & Employee) {
  console.log(`Name: ${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(`Hello, ${user.name}`);
}

型ガード (Type Guards)#

型ガード は、ts において特定の値の実際の型を判断し、その型に基づいてさらなる処理を行う技術です。ユニオン型を使用する際に非常に便利で、異なる型の分岐で適切な操作を正しく実行できるようにします。

  1. typeof 型ガード: 基本型(string, number, boolean など)を判断するために使用します。
function printId(id: string | number) {
  if (typeof id === "string") {
    console.log(id.toUpperCase());
  } else {
    console.log(id.toFixed(2));
  }
}
  1. instanceof 型ガード: オブジェクトが特定のクラスのインスタンスであるかどうかを判断するために使用します。
class Dog {
  bark() {
    console.log("Woof!");
  }
}
class Cat {
  meow() {
    console.log("Meow!");
  }
}
function makeSound(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    animal.bark();
  } else {
    animal.meow();
  }
}
  1. 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));
  }
}
  1. 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: "Alice",
  age: 25,
};
type PersonType = typeof person; // { name: string; age: number; }

// 2、関数の戻り値の型
function getPerson() {
  return { name: "Alice", age: 25 };
}

type PersonType = typeof getPerson(); // { name: string; age: number; }

// 3、JavaScript における型チェック
function printValue(value: number | string) {
  if (typeof value === "string") {
    console.log("This is a string: ", value);
  } else {
    console.log("This is a number: ", 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: "Alice", 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("Hello"); // 文字列は length 属性を持っているため、合法
// logLength(123); // ここではエラーが発生します。number 型には length 属性がありません。

as の役割は何ですか?いつ使用しますか?#

let someValue: any = "This is a string";

// 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 = ["Hello", 42]; // 合法
// tuple = [42, "Hello"]; // 非合法、順序が間違っています。
function getUserInfo(): [string, number] {
  return ["Alice", 25];
}

let entry: [string, number] = ["score", 100];
console.log(entry[0]); // "score" を出力

// オプション要素のタプル
type FlexibleTuple = [string, number?, boolean?];
let tuple1: FlexibleTuple = ["Hello"];

関数のオーバーロードとは何ですか?どのような役割がありますか?#

// オーバーロードシグネチャ(実装なし)
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 `Hello, ${firstName} ${lastName}!`;
  } else {
    return `Hello, ${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 ? "Yes" : "No";

type A = IsString<string>;  // "Yes"
type B = IsString<number>;  // "No"

よく使われる組み込みのユーティリティ型は何ですか?#

Partial<T>#

型 T のすべての属性をオプション属性に変換します。

  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: "Home Page" },
  about: { title: "About Us" },
  contact: { title: "Contact Us" },
};

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: "Alice", age: 25 };
}

type UserType = ReturnType<typeof getUser>;
// UserType は { name: string; age: number; } と等価です。

InstanceType<T>#

コンストラクタ関数型 T のインスタンスタイプを取得します。

class Person {
  name: string = "Alice";
  age: number = 25;
}

type PersonInstance = InstanceType<typeof Person>;
// PersonInstance は Person と等価です。

Parameters<T>#

関数型 T のパラメータ型を取得し、タプル型を返します。

function greet(name: string, age: number): string {
  return `Hello ${name}, you are ${age} years old.`;
}

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="Hello, World!" />
</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": ""
}
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。