{}const=>[]async()letfn</>var
開発キャリアWeb

TypeScriptの面接で最もよくある質問

TypeScriptの面接の準備をしていますか?基本的な概念から高度なテクニックまで、インタビューで最もよく聞かれる質問を分析します。ジェネリック、タイプガード、ユーティリティタイプ、マップされたタイプなど、コード例と説明が含まれます。

К

Kodik

著者

calendar_today
schedule6分で読める

採用担当者が「TypeScriptの基本知識が必要です」と書いているのに、面接では共変性と反変性について尋ねられる瞬間をご存知ですか?はい、はい、私たちは皆それを経験しました。TypeScriptの面接で実際に何を尋ねられているのか、そしてドキュメントだけでなくコンパイラのソースコードも読んだ人のように見えるように答える方法を理解する時が来ました(ネタバレ:必須ではありません)。

面接でよく聞かれる質問を分析してみましょう。しかし、単に「インターフェースとは何か」ではなく、実際の状況と、なぜそれが誰かを気にするのかの説明をします。

1.interfacetypeの違いは何ですか?」

難易度:答え始めるまで、簡単に思える

これは、「ピザとパスタの違いは何ですか?」という質問のようなものです。どちらも生地で作られていて、どちらもイタリア産ですが、食べ方が異なります。

急いでいる人のための簡単な回答:

  • interface – オブジェクト用。拡張可能で、複数回宣言できます(declaration merging)

  • type – union、intersection、プリミティブを含むその他すべて

インプレッションの詳細な回答:

// インターフェースは継承と追加が好きです
interface User {
  name: string;
}

interface User {
  age: number; // 前のものと統合されます!
}

// Typeはエイリアスであり、上書きすることはできません
type Product = {
  id: number;
}

// type Product = { ... } // ❌ エラー!

// しかし、typeは素晴らしいことができます。
type Status = 'pending' | 'success' | 'error';
type Response<T> = { data: T } | { error: string };

面接で言うべきこと: 「実際には、拡張可能なデータ構造(APIタイプなど)を記述するためにinterfaceを使用し、ユニオンタイプ、ユーティリティ、およびより複雑な構造にはtypeを使用します。宣言のマージにより、オブジェクトにはインターフェースの方が適しています。

🔥 10万人以上の学生が参加中

理論を読むのに疲れた?
コーディングの時間だ!

Kodik — 実践でプログラミングを学ぶアプリ。AIメンター、インタラクティブなレッスン、実際のプロジェクト。

🤖 AI 24時間
🎓 修了証
💰 無料
🚀 始める
今日参加

2.「ジェネリックとは何か、なぜ必要なのか?」

難易度:怖いように聞こえるが、実際には論理的

ジェネリックは、Wordのテンプレートのようなものです。一度書いたら、どんなデータでも代入できます。

// ジェネリックなし - 痛みと苦しみ
function getFirstElementString(arr: string[]): string {
  return arr[0];
}

function getFirstElementNumber(arr: number[]): number {
  return arr[0];
}

// ジェネリックを使用 - 一度だけで永久に
function getFirstElement<T>(arr: T[]): T {
  return arr[0];
}

const firstString = getFirstElement(['a', 'b']); // string
const firstNumber = getFirstElement([1, 2, 3]); // number

上級レベル(驚かせるために):

// 制限付きのジェネリック
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: 'Alexey', age: 25 };
getProperty(user, 'name'); // ✅ OK
getProperty(user, 'salary'); // ❌ コンパイルエラー!

3.unknown vs any vs neverを説明してください」

難易度:タイプの世界における哲学的な疑問

想像してみてください:anyは「気にしない」、unknownは「わからないけど確認する」、neverは「それはあり得ない」です。

// any - 無秩序、好きなようにする
let chaos: any = 5;
chaos.doWhatever(); // コンパイラー:「わかった、それはあなたの問題だ」
// 不明 - 安全な不確実性
let mystery: unknown = 5;
// mystery.doSomething (); //❌エラー!

// まずは確認してみましょう
if (typeof mystery === 'number') {
  mystery.toFixed(2); // ✅ これでOK
}

// never - 到達不可能なコードの場合
function throwError(message: string): never {
  throw new Error(message);
  // ここにコードが届くことはありません
}

type Shape = Circle | Square;
function getArea(shape: Shape) {
  switch(shape.kind) {
    case 'circle': return Math.PI * shape.radius ** 2;
    case 'square': return shape.size ** 2;
    default:
      const _exhaustive: never = shape; // 完全性の確認
      return _exhaustive;
  }
}

黄金律: タイプがわからない場合は、anyの代わりにunknownを使用してください。同僚はあなたに感謝するでしょう。

4.「ユーティリティタイプとは何ですか?どれを使用しますか?」

難易度:実際のプロジェクトに取り組んだことがあるかどうかを示します

ユーティリティタイプは、TypeScriptに組み込まれたヘルパーです。これは、タイプのスイスナイフのようなものです。

interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

// 部分的 - すべてのフィールドはオプションです
type UserUpdate = Partial<User>;
// { id?: number; name?: string; ... }

// ピック - 必要なフィールドを選択します
type UserPreview = Pick<User, 'id' | 'name'>;
// { id: number; name: string }

// Omit - フィールドを除外する
type UserPublic = Omit<User, 'password'>;
// { id: number; name: string; email: string }

// レコード - 構造を作成する
type UserRoles = Record<'admin' | 'user' | 'guest', string[]>;
// { admin: string[]; user: string[]; guest: string[] }

// ReturnType - 戻り値のタイプ
function getUser() {
  return { id: 1, name: 'Alex' };
}
type User = ReturnType<typeof getUser>;

ソビエト社会主義共和国連邦のライフハック: ReadonlyRequiredNonNullableに言及して、人気のものだけでなく、知っていることを示してください。

5.「Type Guards とは何か、そしてそれらをどのように作成するか?」

難易度: 中程度、ただし非常に実用的

Type Guardsは、どのデータ型が目の前にあるかを知っていることをTypeScriptに確信させる方法です。

// シンプルなタイプガード
function isString(value: unknown): value is string {
  return typeof value === 'string';
}

// より複雑な
interface Cat {
  meow: () => void;
}

interface Dog {
  bark: () => void;
}

function isCat(animal: Cat | Dog): animal is Cat {
  return (animal as Cat).meow !== undefined;
}

function makeSound(animal: Cat | Dog) {
  if (isCat(animal)) {
    animal.meow(); // TypeScriptはこれがCatであることを知っています
  } else {
    animal.bark(); // そしてここには、犬がいます
  }
}

// 'in'演算子を使用する
type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ('swim' in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

6.keyoftypeofについて教えてください」

難易度:ここでは中級者と初級者が分かれます

interface User {
  id: number;
  name: string;
  email: string;
}

// keyof - すべてのキーのunionを取得します
type UserKeys = keyof User; // 'id' | 'name' | 'email'

// typeof - 値からタイプを取得します
const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000,
  retries: 3
};

type Config = typeof config;
// { apiUrl: string; timeout: number; retries: number }

// コンボ: keyof typeof
const Colors = {
  red: '#ff0000',
  blue: '#0000ff',
  green: '#00ff00'
} as const;

type ColorKey = keyof typeof Colors; // 'red' | 'blue' | 'green'

// 実用化
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

7.「マップされたタイプとは何ですか?」

難易度: シニアテリトリー

Mapped Typesは、錬金術師のように、あるタイプを別のタイプに変えるものです。

type User = {
  name: string;
  age: number;
  email: string;
}

// すべてのフィールドを読み取り専用にする
type ReadonlyUser = {
  readonly [K in keyof User]: User[K];
};

// すべてのフィールドをオプションにする
type PartialUser = {
  [K in keyof User]?: User[K];
};

// すべてのフィールドをnull可能にする
type NullableUser = {
  [K in keyof User]: User[K] | null;
};

// ゲッターを作成する
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type UserGetters = Getters<User>;
// {
//   getName: () => string;
//   getAge: () => number;
//   getEmail: () => string;
// }

8.enumタイプとunionタイプの違いは何ですか?」

難易度:簡単な質問

// Enum - 実際のJavaScriptオブジェクトを作成します
enum Status {
  Pending = 'PENDING',
  Success = 'SUCCESS',
  Error = 'ERROR'
}

console.log(Status.Pending); // 'PENDING'はランタイムに存在します!

// ユニオン - タイプレベルのみ
type StatusUnion = 'PENDING' | 'SUCCESS' | 'ERROR';

// ランタイムでは、これは単なる文字列です
const status: StatusUnion = 'PENDING';

// Const enum - 値にコンパイルされます
const enum Direction {
  Up,
  Down,
  Left,
  Right
}

const dir = Direction.Up; // 0 に変換されます

何を言うべきか: 「私は、シンプルな場合は、ランタイムコードを追加しないため、unionタイプを好みます。フィードバック(逆マッピング)が必要な場合、または実行時に値が必要な場合は、Enumを使用します。

9.「条件付き型とは何ですか?」

難易度:これを理解したなら、あなたはもう初心者ではありません

条件付き型は、型の三項演算子です。

// 基本構文
type IsString<T> = T extends string ? true : false;

type A = IsString<string>; // true
type B = IsString<number>; // false

// 実例
type Flatten<T> = T extends Array<infer U> ? U : T;

type StrArray = Flatten<string[]>; // string
type Num = Flatten<number>; // number

// もっとクールに
type NonNullable<T> = T extends null | undefined ? never : T;

type MaybeString = string | null | undefined;
type DefinitelyString = NonNullable<MaybeString>; // string

// Distributed Conditional Types
type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArray = ToArray<string | number>;
// string[] | number[]

10.inferキーワードについて教えてください」

難易度:これはすでに魔法です

infer を使用すると、別のタイプからタイプを「引き出す」ことができます。

// 関数の戻り値の型を取得します
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function getUser() {
  return { id: 1, name: 'Alex' };
}

type User = ReturnType<typeof getUser>; // { id: number; name: string }

// 配列要素のタイプを取得します
type ArrayElement<T> = T extends (infer U)[] ? U : never;

type NumArray = number[];
type Num = ArrayElement<NumArray>; // number

// 関数パラメータのタイプを取得します
type Parameters<T> = T extends (...args: infer P) => any ? P : never;

function createUser(name: string, age: number) {}

type CreateUserParams = Parameters<typeof createUser>; // [string, number]

// プロミス
type Awaited<T> = T extends Promise<infer U> ? U : T;

type AsyncResult = Awaited<Promise<string>>; // string

💡 では、どのようにこれらすべてを覚えて、適用し始めるのでしょうか?

正直なところ、記事を読むのは素晴らしいことですが、練習しなければ、1週間で忘れてしまいます。実際にコードを書いて、問題に直面する必要があります。

だからこそ、私たちはコディックを作りました – 理論がすぐに実践に移されるアプリケーション。終わりのない講義はありません。コードと課題だけです。

さらに、私たちには 2000人以上の開発者コミュニティとのTelegramチャンネル、毎日役立つ投稿、タスクの分析、ミーム(それらなしではどこへ)、ディスカッションが公開されます。これはStack Overflowのようなものですが、人間的でロシア語です。

追加で尋ねられる可能性のある質問:

11.「Declaration Mergingとは何ですか?」

interface Box {
  height: number;
}

interface Box {
  width: number;
}

// TypeScriptは両方を次のように結合します。
// interface Box {
//   height: number;
//   width: number;
// }

12.as constが必要な理由は?」

// as constなし
const colors = ['red', 'blue']; // string[]

// C as const
const colorsConst = ['red', 'blue'] as const; // readonly ['red', 'blue']

// 実用化
const routes = {
  home: '/',
  about: '/about',
  contact: '/contact'
} as const;

type Route = typeof routes[keyof typeof routes]; 
// '/' | '/about' | '/contact'

13.「テンプレートリテラルタイプとは何ですか?」

type Direction = 'up' | 'down' | 'left' | 'right';
type Move = `move${Capitalize<Direction>}`; 
// 'moveUp' | 'moveDown' | 'moveLeft' | 'moveRight'

type EventName = 'click' | 'focus' | 'blur';
type Handler = `on${Capitalize<EventName>}`;
// 'onClick' | 'onFocus' | 'onBlur'

結論:面接の準備方法

1 週間前:

  1. TypeScriptの公式ドキュメントを読んでください

  2. Type Challengesのタスクを解決する( github.com/type-challenges/type-challenges )

  3. コンセプトを声に出して説明する練習をする

前日:

  1. この記事の基本的な概念を繰り返す

  2. 自分のプロジェクトから例を用意する

  3. 十分な睡眠をとる(これは暗記よりも重要です)

面接時:

  • 「知らないけど、探してみるよ」と言うことを恐れないでください。

  • ドキュメントを引用するよりも、自分の言葉でコンセプトを説明する方が良い

  • 質問をすることで、あなたが考えていることを示すことができます

主な内容: TypeScriptはツールであり、それ自体が目的ではありません。 なぜ 型指定が必要です。すべてのユーティリティタイプを暗記することが重要です。

P.S. 読んだ後、頭の中が混乱している場合は、それは普通です。TypeScriptは一晩で学べるものではありません。この記事に戻って、例を試し、間違いを犯し、学びましょう。それがすべての仕組みです。

面接がうまくいきますように!コンパイラがあなたの味方になりますように✨

🎯先延ばしをやめよう

記事は気に入った?
実践の時間だ!

Kodikでは読むだけでなく、すぐにコードを書く。理論 + 実践 = 本当のスキル。

即座に実践
🧠AIがコードを説明
🏆修了証

登録不要 • カード不要