mosya<TC> - 配列に要素が含まれればtrueを返す型を作ろう
この記事はmosya<TC>の問題の一つであるIncludes型の解説になります。
問題
JavaScriptのArray.include
関数を型システムに実装します。この型は、2つの引数を受け取り、true
やfalse
を出力しなければなりません。
例えば以下のようなコードを満たすようにIf
型を実装しましょう。
type isPillarMen = Includes<
[
"Kars",
"Esidisi",
"Wamuu",
"Santana"
],
"Dio"
>; // expected to be `false`
前提知識
この問題を解くにあたって型についての以下の知識を理解しておく必要があります。
- ジェネリクスを理解する
- Conditional Typesを理解する
- インデックスアクセス型を理解する
ジェネリクスを理解する
まず、<T>というのは、ジェネリクスと呼ばれる機能です。ジェネリクスは、型をパラメータとして受け取ることができる機能です。
この受け取った値を使って、新しい型を生成することができます。
受け取った型を活用して、新しい型を生成することができるので、型の再利用性が高くなります。
例えば、以下のような型が考えられます
type Foo<T> = {
bar: T;
};
この型は、T
という型を受け取り、bar
というプロパティにT
を代入する型です。
この型を使うと、以下のように型を指定することができます。
type FooString = Foo<string>; // { bar: string }
type FooNumber = Foo<number>; // { bar: number }
このようにジェネリクスは型を引数として受け取って、新しい型を生成することができます。
型の制約
T
はextends
をつけることで制約をつけることができます。
例えば、T extends string
とすると、T
はstring
型かstring
型を継承した型に制約されます。
Conditional Typesを理解する
Conditional Typesは、条件によって型を変更することができる機能です。
例えば、以下のような型が考えられます。
type Foo<T> = T extends string
? string
: number;
この型は、T
がstring
型を継承している場合はstring
型を、そうでない場合はnumber
型を返します。
この型を使うと、以下のように型を指定することができます。
type FooString = Foo<string>; // string
type FooNumber = Foo<boolean>; // number
このようにConditional Typesは、条件によって型を変更することができます。
インデックスアクセス型を理解する
インデックスアクセス型
は、オブジェクトのプロパティにアクセスするための機能です。
例えば、以下のようなオブジェクトがあったとします。
interface Todo {
title: string;
description: string;
}
このオブジェクトのプロパティにアクセスするには、以下のようにします。
type Title = Todo["title"]; // string
このように、Todo["title"]
とすることで、Todo
のtitle
プロパティの型を取得することができます。
これをインデックスアクセス型と呼びます。
このインデックスアクセス型は配列にも使うことができます。
type Cars = [
"Toyota",
"Honda",
"Nissan"
];
type Car = Cars[0]; // "Toyota"
また、number
を使うことで、配列の要素の型をユニオン型として取得することができます。
type Cars = [
"Toyota",
"Honda",
"Nissan"
];
type Car = Cars[number]; // "Toyota" | "Honda" | "Nissan"
解答例
以上の前提知識を踏まえて、以下のように解答することができます。
type Includes<
T extends readonly any[],
U
> = U extends T[number] ? true : false;
この解答例では、T extends readonly any[]
という制約をつけています。
これにより、T
は配列であり、変更不可能な配列であることが保証されます。
T[number]
により配列の値がユニオン型として取得されます。
よって、U
がT[number]
のどれかに当てはまる場合はtrue
を、そうでない場合はfalse
を返すことになります。
Authored by
Godai@steelydylan
Webサービスを作るのが好きなWebエンジニア。子供が産まれたことをきっかけに独立し法人化。サービス開発が大好き。
好きな言語はTypeScript。