This article was translated from Japanese by AI and may contain
inaccuracies. For the most accurate content, please refer to the original Japanese version.
このケースに対応するため配列が空かどうかチェックし空の配列なら never を返し、そうでないなら配列の先頭の型を返すという条件分岐が必要です。型システム上で条件分岐を実装するには Conditional Types を使用します。空の配列かどうかの条件部には T extends [] と記述します。
回答例
type First<T extends any[]> = T extends [] ? never : T[0]
Length of Tuple
For given a tuple, you need create a generic Length, pick the length of the tuple
しかし、これだけだと T が本当に length プロパティを持っているかどうかわからないので、以下のようなエラーが出力されてしまします。
Type '"length"' cannot be used to index type 'T'.
T が length プロパティを持っていることを伝えるために extends { length: number } のように制約を持たせることも可能ですが、この指定方法ですとタプルだけでなく string のような型も引数として渡せてしますので、適切ではありません。これを踏まえた回答例は以下になります。
回答例
type Length<T extends readonly any[]> = T['length']
if
Implement a utils If which accepts condition C, a truthy return type T, and a falsy return type F. C is expected to be either true or false while T and F can be any type.
For example:
type A = If<true, 'a', 'b'> // expected to be 'a'type B = If<false, 'a', 'b'> // expected to be 'b'
Exclude<T, U> は U に割り当て可能な型を T から除外する型です。 Union Types から特定の型を取り除く際に使われます。
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"type T2 = Exclude<string | number | (() => void), Function>; // string | number
この課題を解くにあたり重要になるポイントは Conditional Types が分配法則(Distributive) に従うと
いう点です。Conditional Types の条件部において T extends U の T がユニオン型である場合 T に対して反復処理を行い各要素に条件を適用します。
type ToArray<Type> = Type extends any ? Type[] : never;type StrArrOrNumArr = ToArray<string | number>; // string[] | number[]
そのため、回答例としては T の各要素を反復し T が U を拡張可能であれば never を返しそうでないなら T を返すようにすればよいです。
回答例
type MyExclude<T, U> = T extends U ? never : T
Awaited
If we have a type which is wrapped type like Promise. How we can get a type which is inside the wrapped type? For example if we have Promise<ExampleType> how to get ExampleType?
type Awaited<T extends Promise<any>> = T extends Promise<string> ? string : never
他にも number や boolean の例も出してみましょう。
type Awaited<T extends Promise<any>> = T extends Promise<number> ? number : nevertype Awaited<T extends Promise<any>> = T extends Promise<boolean> ? boolean : never
この型を特定の型だけでなく一般性を持たせるためには T が Promise<U> を拡張可能であるならば U を返すという記述をすればよさそうです。しかし、U という型変数はどこから取得すればよいのでしょうか? Promise<any> という型を受け取ったうえで、実際に条件が評価されるタイミングになったらその具体的な型を代入したいということをしたいのです。
このような場合には infer キーワードが使えます。infer は conditional type のみで使用できます。infer は「推論」を意味する単語であり、その型になにかわかった時点で型変数にその値を代入します。
回答例
type Awaited<T extends Promise<any>> = T extends Promise<infer U> ? U : never
Parameters
Implement the built-in Parameters generic without using it.
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer U) => any ? U : never
Concat
Implement the JavaScript Array.concat function in the type system. A type takes the two arguments. The output should be a new array that includes inputs in ltr order
For example
type Result = Concat<[1], [2]> // expected to be [1, 2]