type-challengesを実践する

リポジトリ
参考記事
まずはクローンする
git clone git@github.com:type-challenges/type-challenges.git
インストールする
pnpm install
pnpm generate
pnpmのバージョンが合わずに以下のエラーが出る場合がある
ERR_PNPM_BAD_PM_VERSION This project is configured to use v8.12.1 of pnpm. Your current pnpm is v9.0.5
以下のコマンドでエラーを回避する
pnpm config set package-manager-strict false
再度pnpm generate
を実行し、言語を選択する
Generating local playground...
✔ Select language: › ja
Local playground generated at:
playground
ディレクトリに選択した言語のチャレンジファイルが生成される

00004-easy-pick
/*
4 - Pick
-------
by Anthony Fu (@antfu) #初級 #union #built-in
### 質問
組み込みの型ユーティリティ`Pick<T, K>`を使用せず、`T`から`K`のプロパティを抽出する型を実装します。
例えば:
```ts
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
}
```
> GitHubで確認する:https://tsch.js.org/4/ja
*/
/* _____________ ここにコードを記入 _____________ */
type MyPick<T, K extends keyof T> = {
[key in K]: T[key];
};
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Expected1, MyPick<Todo, 'title'>>>,
Expect<Equal<Expected2, MyPick<Todo, 'title' | 'completed'>>>,
// @ts-expect-error
MyPick<Todo, 'title' | 'completed' | 'invalid'>,
]
interface Todo {
title: string
description: string
completed: boolean
}
interface Expected1 {
title: string
}
interface Expected2 {
title: string
completed: boolean
}
keyof 演算子
オブジェクト型からそのプロパティ名を型として取得します。
例: keyof Todo
は 'title' | 'description' | 'completed'
という型になります。
インデックス型アクセス:
オブジェクト型から特定のプロパティの型を取得します。
例: Todo['title']
は string
型になります。
マップ型の基本:
新しいオブジェクト型を作る方法です。
[K in ...]
の部分で、どのキーを使うかを指定します。
例: { [K in 'a' | 'b']: string }
は { a: string; b: string }
という型になります。
これらを組み合わせて MyPick
を作ります:
typescriptCopytype MyPick<T, K extends keyof T> = {
[key in K]: T[key];
};
- T は元のオブジェクト型(例: Todo)
- K は選びたいプロパティ名の型(例: 'title' | 'completed')
- K extends keyof T で、K が必ず T のプロパティ名であることを保証
- [key in K] で、選んだプロパティ名それぞれに対して処理
- T[key] で、元の型からプロパティの型を取得

00007-easy-readonly
/*
7 - Readonly
-------
by Anthony Fu (@antfu) #初級 #built-in #readonly #object-keys
### 質問
組み込みの型ユーティリティ`Readonly<T>`を使用せず、`T` のすべてのプロパティを読み取り専用にする型を実装します。実装された型のプロパティは再割り当てできません。
例えば:
```ts
interface Todo {
title: string
description: string
}
const todo: MyReadonly<Todo> = {
title: "Hey",
description: "foobar"
}
todo.title = "Hello" // Error: cannot reassign a readonly property
todo.description = "barFoo" // Error: cannot reassign a readonly property
```
> GitHubで確認する:https://tsch.js.org/7/ja
*/
/* _____________ ここにコードを記入 _____________ */
type MyReadonly<T> = {
readonly [K in keyof T]: T[K]
}
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>,
]
interface Todo1 {
title: string
description: string
completed: boolean
meta: {
author: string
}
}
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/7/answer/ja
> 解答を見る:https://tsch.js.org/7/solutions
> その他の課題:https://tsch.js.org/ja
*/
type MyReadonly<T> = ...
役割: ジェネリック型 MyReadonly
を定義します。
T
は型パラメータで、この型を使用する際に具体的な型が渡されます。
{ ... }
役割: 新しいオブジェクト型を作成することを示します。
readonly
役割: 各プロパティを読み取り専用にするための修飾子です。
これにより、生成される新しい型の全てのプロパティが変更不可能になります。
[K in keyof T]
役割: Mapped Types
の構文で、T
の全てのプロパティに対してイテレーションを行います。
keyof T: 型 T の全てのプロパティ名を Union 型として取得します。
K in ...: 取得した Union 型の各要素に対して処理を行うことを示します。
K は各イテレーションでの現在のプロパティ名を表す型変数です。
: T[K]
役割: 元の型 T から、現在のプロパティ K に対応する型を取得します。
これにより、新しい型で元の型の構造(各プロパティの型)を維持します。

00011-easy-tuple-to-object
/*
11 - Tuple to Object
-------
by sinoon (@sinoon) #初級 #object-keys
### 質問
タプルを受け取り、その各値のkey/valueを持つオブジェクトの型に変換する型を実装します。
例えば:
```ts
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
type result = TupleToObject<typeof tuple> // expected { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y'}
```
> GitHubで確認する:https://tsch.js.org/11/ja
*/
/* _____________ ここにコードを記入 _____________ */
type TupleToObject<T extends readonly (string | number | symbol)[]> = {
[key in T[number]]: key
}
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
const tupleNumber = [1, 2, 3, 4] as const
const sym1 = Symbol(1)
const sym2 = Symbol(2)
const tupleSymbol = [sym1, sym2] as const
const tupleMix = [1, '2', 3, '4', sym1] as const
type cases = [
Expect<Equal<TupleToObject<typeof tuple>, { 'tesla': 'tesla', 'model 3': 'model 3', 'model X': 'model X', 'model Y': 'model Y' }>>,
Expect<Equal<TupleToObject<typeof tupleNumber>, { 1: 1, 2: 2, 3: 3, 4: 4 }>>,
Expect<Equal<TupleToObject<typeof tupleSymbol>, { [sym1]: typeof sym1, [sym2]: typeof sym2 }>>,
Expect<Equal<TupleToObject<typeof tupleMix>, { 1: 1, '2': '2', 3: 3, '4': '4', [sym1]: typeof sym1 }>>,
]
// @ts-expect-error
type error = TupleToObject<[[1, 2], {}]>
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/11/answer/ja
> 解答を見る:https://tsch.js.org/11/solutions
> その他の課題:https://tsch.js.org/ja
*/
元の課題
type TupleToObject<T extends readonly any[]> = any
-
まずany[]に想定される型を設定
type TupleToObject<T extends readonly (string | number | symbol)[]> = any
-
T[number] により、与えられるタプルからユニオン型を生成
type TupleToObject<T extends readonly (string | number | symbol)[]> = { [T[number]]: key }
-
[key in ...] が、生成されたユニオン型の各要素に対してイテレートをする
type TupleToObject<T extends readonly (string | number | symbol)[]> = { [key in T[number]]: key }
-
結果として、オブジェクト型が生成される
[number]を使う理由:
- 全要素へのアクセス
配列やタプルの特定のインデックス(例:[0], [1])ではなく、全ての要素にアクセスしたい場合に使用します。
- 型の抽出
配列やタプルから、含まれうる全ての要素の型を一度に取得できます。
- 動的な長さへの対応
タプルや配列の長さが不定の場合でも、全ての要素の型を取得できます。
- ユニオン型の生成
タプルの場合、各要素のリテラル型のユニオンを生成します。これは、タプルの各要素を個別の型として扱いたい場合に有用です。
[number]の動作:
- 配列の場合:配列の要素型を返します。
- タプルの場合:タプルの全要素のリテラル型のユニオンを返します。

00014-easy-first-of-array
/*
14 - First of Array
-------
by Anthony Fu (@antfu) #初級 #array
### 質問
配列`T`を受け取り、その最初のプロパティの型を返す`First<T>`を実装します。
例えば:
```ts
type arr1 = ['a', 'b', 'c']
type arr2 = [3, 2, 1]
type head1 = First<arr1> // expected to be 'a'
type head2 = First<arr2> // expected to be 3
```
> GitHubで確認する:https://tsch.js.org/14/ja
*/
/* _____________ ここにコードを記入 _____________ */
type First<T extends any[]> = any
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<First<[3, 2, 1]>, 3>>,
Expect<Equal<First<[() => 123, { a: string }]>, () => 123>>,
Expect<Equal<First<[]>, never>>,
Expect<Equal<First<[undefined]>, undefined>>,
]
type errors = [
// @ts-expect-error
First<'notArray'>,
// @ts-expect-error
First<{ 0: 'arrayLike' }>,
]
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/14/answer/ja
> 解答を見る:https://tsch.js.org/14/solutions
> その他の課題:https://tsch.js.org/ja
*/
extends キーワードの役割
TypeScriptでは、extends
は「型の制約
」や「型の条件チェック
」に使用されます。
A extends B
は、「AがBの部分型(subset)であるか、またはBと同じ型であるか
」をチェックします。
これを用いて、T
が配列であるかどうかをチェックし、配列が空であればnever
配列が空でなければ配列(T
)の0番目を返すようにする。
type First<T extends any[]> = T extends [] ? never : T[0];

00018-easy-length-of-tuple
/*
18 - Length of Tuple
-------
by sinoon (@sinoon) #初級 #tuple
### 質問
タプル`T`を受け取り、そのタプルの長さを返す型`Length<T>`を実装します。
例えば:
```ts
type tesla = ['tesla', 'model 3', 'model X', 'model Y']
type spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT']
type teslaLength = Length<tesla> // expected 4
type spaceXLength = Length<spaceX> // expected 5
```
> GitHubで確認する:https://tsch.js.org/18/ja
*/
/* _____________ ここにコードを記入 _____________ */
type Length<T> = any
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
const tesla = ['tesla', 'model 3', 'model X', 'model Y'] as const
const spaceX = ['FALCON 9', 'FALCON HEAVY', 'DRAGON', 'STARSHIP', 'HUMAN SPACEFLIGHT'] as const
type cases = [
Expect<Equal<Length<typeof tesla>, 4>>,
Expect<Equal<Length<typeof spaceX>, 5>>,
// @ts-expect-error
Length<5>,
// @ts-expect-error
Length<'hello world'>,
]
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/18/answer/ja
> 解答を見る:https://tsch.js.org/18/solutions
> その他の課題:https://tsch.js.org/ja
*/
- まずは受け取るものが配列なので、
extends
でTとany型の配列を比較する。その際、as const
で読み取り専用になっているタプルに対応するため、readonly
を付ける。readonly
を使用することで、通常の配列とreadonly
配列の両方を受け入れることができる。type Length<T extends readonly any[]> = any
-
T
の配列のlength
を返す。書き方は以下の通りtype Length<T extends readonly any[]> = T['length']

00043-easy-exclude
/*
43 - Exclude
-------
by Zheeeng (@zheeeng) #初級 #built-in #union
### 質問
組み込みの型ユーティリティ`Exclude <T, U>`を使用せず、`U`に割り当て可能な型を`T`から除外する型を実装します。
例えば:
```ts
type Result = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
```
> GitHubで確認する:https://tsch.js.org/43/ja
*/
/* _____________ ここにコードを記入 _____________ */
type MyExclude<T, U> = any
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyExclude<'a' | 'b' | 'c', 'a'>, 'b' | 'c'>>,
Expect<Equal<MyExclude<'a' | 'b' | 'c', 'a' | 'b'>, 'c'>>,
Expect<Equal<MyExclude<string | number | (() => void), Function>, string | number>>,
]
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/43/answer/ja
> 解答を見る:https://tsch.js.org/43/solutions
> その他の課題:https://tsch.js.org/ja
*/
- これは、
T
とU
を比較して、一致するプロパティ(true
)であればnever
(除外)とし、false
であれば元のT
のままにするtype MyExclude<T, U> = T extends U ? never : T;

00189-easy-awaited
/*
189 - Awaited
-------
by Maciej Sikora (@maciejsikora) #初級 #promise #built-in
### 質問
Promise ライクな型が内包する型をどのように取得すればよいでしょうか。
例えば:`Promise<ExampleType>`という型がある場合、どのようにして ExampleType を取得すればよいでしょうか。
```ts
type ExampleType = Promise<string>
type Result = MyAwaited<ExampleType> // string
```
> この問題の元記事は [original article](https://dev.to/macsikora/advanced-typescript-exercises-question-1-45k4) by [@maciejsikora](https://github.com/maciejsikora) です。
> GitHubで確認する:https://tsch.js.org/189/ja
*/
/* _____________ ここにコードを記入 _____________ */
type MyAwaited<T> = any
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type X = Promise<string>
type Y = Promise<{ field: number }>
type Z = Promise<Promise<string | number>>
type Z1 = Promise<Promise<Promise<string | boolean>>>
type T = { then: (onfulfilled: (arg: number) => any) => any }
type cases = [
Expect<Equal<MyAwaited<X>, string>>,
Expect<Equal<MyAwaited<Y>, { field: number }>>,
Expect<Equal<MyAwaited<Z>, string | number>>,
Expect<Equal<MyAwaited<Z1>, string | boolean>>,
Expect<Equal<MyAwaited<T>, number>>,
]
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/189/answer/ja
> 解答を見る:https://tsch.js.org/189/solutions
> その他の課題:https://tsch.js.org/ja
*/
TypeScript の MyAwaited<T> 型の解説
答えは以下
MyAwaited<T extends PromiseLike<any>> = T extends PromiseLike<infer U>
? U extends PromiseLike<any>
? MyAwaited<U>
: U
: never;
主要概念
1. PromiseLike
PromiseLike は Promise-like なオブジェクトを表す TypeScript の組み込み型です。
PromiseLike<T> {
then<TResult1 = T, TResult2 = never>(
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
): PromiseLike<TResult1 | TResult2>;
}
PromiseLike
は then
メソッドを持つオブジェクトを表します。
Promise
だけでなく、Promise-like
な動作をする他のオブジェクトも含みます。
<T>
は Promise
が解決される値の型を表します。
2. infer キーワード
infer
は条件付き型の中で使用され、型の一部を推論して新しい型変数として使用できるようにします。
UnpackPromise<T> = T extends Promise<infer U> ? U : T;
// 使用例
type Result1 = UnpackPromise<Promise<string>>; // string
type Result2 = UnpackPromise<number>; // number
infer U
は「ここに入る型をU
として推論せよ」という意味です。
上記の例では、Promise<string>
から string
を、Promise<number>
から number
を推論します。
MyAwaited<T> の詳細解説
T extends PromiseLike<any>
これは型パラメータ T
の制約です。
T
は PromiseLike (Promise や thenable オブジェクト)
である必要があります。
T extends PromiseLike<infer U>
条件付き型と infer
キーワードを使用しています。
T
が PromiseLike
であった場合に、その内部の型を U
として推論します。
U extends PromiseLike<any> ? MyAwaited<U> : U
入れ子になった Promise
を処理するための再帰的な定義です。
U
が更に PromiseLike
である場合、MyAwaited<U>
を再帰的に呼び出します。
そうでない場合は U
をそのまま返します。
最後の : never
これは型制約 T extends PromiseLike<any>
を満たさない場合の型です。
実際にはこの行に到達することはありません(型制約により防がれているため)。

00268-easy-if.ts
/*
268 - If
-------
by Pavel Glushkov (@pashutk) #初級 #utils
### 質問
条件値`C`、 `C`が truthy である場合の戻り値の型`T`、`C`が falsy である場合の戻り値の型`F`を受け取る`If`を実装します。
条件値`C` は`true`か`false`のどちらかであることが期待されますが、`T` と `F` は任意の型をとることができます。
例えば:
```ts
type A = If<true, 'a', 'b'>; // expected to be 'a'
type B = If<false, 'a', 'b'>; // expected to be 'b'
```
> GitHubで確認する:https://tsch.js.org/268/ja
*/
/* _____________ ここにコードを記入 _____________ */
type If<C, T, F> = any
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<If<true, 'a', 'b'>, 'a'>>,
Expect<Equal<If<false, 'a', 2>, 2>>,
Expect<Equal<If<boolean, 'a', 2>, 'a' | 2>>,
]
// @ts-expect-error
type error = If<null, 'a', 'b'>
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/268/answer/ja
> 解答を見る:https://tsch.js.org/268/solutions
> その他の課題:https://tsch.js.org/ja
*/
- まずCはbooleanであるとわかっているので、If<C extends boolean, T, F>とする
- Cとtrueをextendsで比較し、trueであればT、falseであればFになる式を記述する
type If<C extends boolean, T, F> = C extends true ? T : F;

00533-easy-concat
/*
533 - Concat
-------
by Andrey Krasovsky (@bre30kra69cs) #初級 #array
### 質問
JavaScript の`Array.concat`関数を型システムに実装します。この型は 2 つの引数を受け取り、受け取ったイテレータの要素を順に含む新しい配列を返します。
例えば:
```ts
type Result = Concat<[1], [2]>; // expected to be [1, 2]
```
> GitHubで確認する:https://tsch.js.org/533/ja
*/
/* _____________ ここにコードを記入 _____________ */
type Concat<T, U> = any
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
const tuple = [1] as const
type cases = [
Expect<Equal<Concat<[], []>, []>>,
Expect<Equal<Concat<[], [1]>, [1]>>,
Expect<Equal<Concat<typeof tuple, typeof tuple>, [1, 1]>>,
Expect<Equal<Concat<[1, 2], [3, 4]>, [1, 2, 3, 4]>>,
Expect<Equal<Concat<['1', 2, '3'], [false, boolean, '4']>, ['1', 2, '3', false, boolean, '4']>>,
]
// @ts-expect-error
type error = Concat<null, undefined>
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/533/answer/ja
> 解答を見る:https://tsch.js.org/533/solutions
> その他の課題:https://tsch.js.org/ja
*/
- TとUをextendsでany[]と比較する
type Concat<T extends any[], U extends any[]> = any
するとtype casesに以下のエラーが出る
型 'readonly [1]' は制約 'any[]' を満たしていません。
型 'readonly [1]' は 'readonly' であるため、変更可能な型 'any[]' に代入することはできません。
- エラーを解決するためにTupleの型をreadonlyで定義する
type Tuple = readonly unknown[];
- TとUをanyではなくTuple型と比較する
type Tuple = readonly unknown[];
type Concat<T extends Tuple, U extends Tuple> = any
- 新しい配列を作る
type Tuple = readonly unknown[];
type Concat<T extends Tuple, U extends Tuple> = [...T,...U]

00898-easy-includes
/*
898 - Includes
-------
by null (@kynefuk) #初級 #array
### 質問
JavaScriptの`Array.include`関数を型システムに実装します。この型は、2 つの引数を受け取り、`true`や`false`を出力しなければなりません。
例えば:
```ts
type isPillarMen = Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Dio'> // expected to be `false`
```
> GitHubで確認する:https://tsch.js.org/898/ja
*/
/* _____________ ここにコードを記入 _____________ */
type Includes<T extends readonly any[], U> = any
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Kars'>, true>>,
Expect<Equal<Includes<['Kars', 'Esidisi', 'Wamuu', 'Santana'], 'Dio'>, false>>,
Expect<Equal<Includes<[1, 2, 3, 5, 6, 7], 7>, true>>,
Expect<Equal<Includes<[1, 2, 3, 5, 6, 7], 4>, false>>,
Expect<Equal<Includes<[1, 2, 3], 2>, true>>,
Expect<Equal<Includes<[1, 2, 3], 1>, true>>,
Expect<Equal<Includes<[{}], { a: 'A' }>, false>>,
Expect<Equal<Includes<[boolean, 2, 3, 5, 6, 7], false>, false>>,
Expect<Equal<Includes<[true, 2, 3, 5, 6, 7], boolean>, false>>,
Expect<Equal<Includes<[false, 2, 3, 5, 6, 7], false>, true>>,
Expect<Equal<Includes<[{ a: 'A' }], { readonly a: 'A' }>, false>>,
Expect<Equal<Includes<[{ readonly a: 'A' }], { a: 'A' }>, false>>,
Expect<Equal<Includes<[1], 1 | 2>, false>>,
Expect<Equal<Includes<[1 | 2], 1>, false>>,
Expect<Equal<Includes<[null], undefined>, false>>,
Expect<Equal<Includes<[undefined], null>, false>>,
]
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/898/answer/ja
> 解答を見る:https://tsch.js.org/898/solutions
> その他の課題:https://tsch.js.org/ja
*/
-
T[number](インデックス型アクセス(Indexed Access Types))
を使用し、配列Tのすべての要素のユニオン型を取得します。例えば、['a', 'b', 'c']であれば、T[number]は 'a' | 'b' | 'c'となります。 - 次に、配列Tの要素をキーとして、すべての値をtrueに設定したマップ型を作成します。
type Includes<T extends readonly any[], U> = {
[key in T[number]]: true
}
- この時点では、Includesは単にマップ型を返します。例えば、Includes<['a', 'b', 'c'], 'a'>は次の型を生成します。
{
'a': true;
'b': true;
'c': true;
}
- 次に、このマップ型を使用して、UがTの要素に含まれているかをチェックします。
type Includes<T extends readonly any[], U> = {
[key in T[number]]: true
}[U];
ここで、[U]
はマップ型のキーアクセスを表し、U
がT
に含まれていればtrue
を返し、含まれていなければundefined
を返します。
5. 最後に、この結果をtrueまたはfalseに変換する必要があります。extendsを使用して、trueかどうかをチェックします。
type Includes<T extends readonly any[], U> = {
[key in T[number]]: true
}[U] extends true ? true : false;

/*
3057 - Push
-------
by jiangshan (@jiangshanmeta) #初級 #array
### 質問
```Array.push```のジェネリックバージョンを実装します。
例えば:
```typescript
type Result = Push<[1, 2], '3'> // [1, 2, '3']
```
> GitHubで確認する:https://tsch.js.org/3057/ja
*/
/* _____________ ここにコードを記入 _____________ */
type Push<T extends unknown[], U> = [...T , U]
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Push<[], 1>, [1]>>,
Expect<Equal<Push<[1, 2], '3'>, [1, 2, '3']>>,
Expect<Equal<Push<['1', 2, '3'], boolean>, ['1', 2, '3', boolean]>>,
]
/* _____________ 次のステップ _____________ */
/*
> 解答を共有する:https://tsch.js.org/3057/answer/ja
> 解答を見る:https://tsch.js.org/3057/solutions
> その他の課題:https://tsch.js.org/ja
*/
- まず、第一引数はunknownの配列なのでextendsで比較します
type Push<T extends unknown[], U> = any;
- 次に、スプレッド構文で第二引数Uを追加した新しい配列を生成します
type Push<T extends unknown[], U> = [...T , U]

3060 - Unshift
/*by jiangshan (@jiangshanmeta) #初級 #array
質問
Array.unshift
の型バージョンを実装します。
例えば:
type Result = Unshift<[1, 2], 0> // [0, 1, 2]
GitHubで確認する:https://tsch.js.org/3060/ja
*/
/* _____________ ここにコードを記入 _____________ */
type Unshift<T extends unknown[], U> = [U, ...T];
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<Unshift<[], 1>, [1]>>,
Expect<Equal<Unshift<[1, 2], 0>, [0, 1, 2]>>,
Expect<Equal<Unshift<['1', 2, '3'], boolean>, [boolean, '1', 2, '3']>>,
]
/* _____________ 次のステップ _____________ /
/
解答を共有する:https://tsch.js.org/3060/answer/ja
解答を見る:https://tsch.js.org/3060/solutions
その他の課題:https://tsch.js.org/ja
*/
- まず第一引数はunknonwnの配列なのでTをextendsで指定する
type Unshift<T extends unknown[], U> = any;
- 第二引数を先頭とした新しい配列をスプレッド構文で生成する
type Unshift<T extends unknown[], U> = [U, ...T];

3312 - Parameters
/*by midorizemi (@midorizemi) #初級 #infer #tuple #built-in
質問
組み込みの型ユーティリティParameters<T>
を使用せず、T
からタプル型を構築する型を実装します。
例えば:
const foo = (arg1: string, arg2: number): void => {}
type FunctionParamsType = MyParameters<typeof foo> // [arg1: string, arg2: number]
GitHubで確認する:https://tsch.js.org/3312/ja
*/
/* _____________ ここにコードを記入 _____________ */
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
/* _____________ テストケース _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
function foo(arg1: string, arg2: number): void {}
function bar(arg1: boolean, arg2: { a: 'A' }): void {}
function baz(): void {}
type cases = [
Expect<Equal<MyParameters<typeof foo>, [string, number]>>,
Expect<Equal<MyParameters<typeof bar>, [boolean, { a: 'A' }]>>,
Expect<Equal<MyParameters<typeof baz>, []>>,
]
/* _____________ 次のステップ _____________ /
/
解答を共有する:https://tsch.js.org/3312/answer/ja
解答を見る:https://tsch.js.org/3312/solutions
その他の課題:https://tsch.js.org/ja
*/
- Tをinferキーワードを使って推論します。
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P)
- T が関数型である場合には、推論された引数型 P を返し、それ以外の場合には never を返します。
type MyParameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
infer キーワードの詳細解説
infer キーワードは、TypeScriptの条件型 (conditional types) と共に使われる特殊なキーワードで、型の一部を推論するために使用されます。
特に、型の一部を抽出したり、再利用する際に便利。