感谢
感谢 type-challenges (opens new window) 这个项目,在初步学习 TypeScript 后得到了良好的练习。
工具
该项目提供了一些基础的工具来帮助测试。
对错
type Expect<T extends true> = T
type ExpectTrue<T extends true> = T
type ExpectFalse<T extends false> = T
type IsTrue<T extends true> = T
type IsFalse<T extends true> = T
1
2
3
4
5
2
3
4
5
相等
type Equal<X, Y> =
(<T>() => T extends X ? 1 : 2) extends
(<T>() => T extends Y ? 1 : 2) ? true : false
type NotEqual<X, Y> = true extends Equal<X, Y> ? false : true
1
2
3
4
2
3
4
any
type IsAny<T> = 0 extends (1 & T) ? true : false
type NotAny<T> = true extends IsAny<T> ? false : true
1
2
2
其他
export type Debug<T> = { [K in keyof T]: T[K] }
export type MergeInsertions<T> =
T extends object
? { [K in keyof T]: MergeInsertions<T[K]> }
: T
export type Alike<X, Y> = Equal<MergeInsertions<X>, MergeInsertions<Y>>
export type ExpectExtends<VALUE, EXPECTED> = EXPECTED extends VALUE ? true : false
export type ExpectValidArgs<FUNC extends (...args: any[]) => any, ARGS extends any[]> = ARGS extends Parameters<FUNC>
? true
: false
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
练习
Hello World
import { Equal, Expect, NotAny } from '@type-challenges/utils'
type HelloWorld = string
type cases = [
Expect<NotAny<HelloWorld>>,
Expect<Equal<HelloWorld, string>>
]
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Pick
import { Equal, Expect } from '@type-challenges/utils'
type MyPick<T, K> = any
interface Todo {
title: string
description: string
completed: boolean
}
interface Expected1 {
title: string
}
interface Expected2 {
title: string
completed: boolean
}
type cases = [
Expect<Equal<Expected1, Pick<Todo, 'title'>>>,
Expect<Equal<Expected2, Pick<Todo, 'title' | 'completed'>>>
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Readonly
import { Equal, Expect } from '@type-challenges/utils'
type MyReadonly<T> = {
readonly [K in keyof T]: T[K]
}
interface Todo1 {
title: string
description: string
completed: boolean
}
type cases = [
Expect<Equal<MyReadonly<Todo1>, Readonly<Todo1>>>
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Tuple to Object
import { Equal, Expect } from '@type-challenges/utils'
type TupleToObject<T extends readonly any[]> = {
[K in T[number]]: K
}
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
type cases = [
Expect<Equal<TupleToObject<typeof tuple>, { tesla: 'tesla'; 'model 3': 'model 3'; 'model X': 'model X'; 'model Y': 'model Y'}>>,
]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
First of Array
import { Equal, Expect } from '@type-challenges/utils'
type First<T extends any[]> = T extends [] ? never : T[0]
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>>
]
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Length of Tuple
import { Equal, Expect } from '@type-challenges/utils'
type Length<T extends readonly any[]> = T['length']
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>>,
]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Exclude
import { Equal, Expect } from '@type-challenges/utils'
type MyExclude<T, U> = T extends U ? never : T
type cases = [
Expect<Equal<MyExclude<'a' | 'b' | 'c', 'a'>, Exclude<'a' | 'b' | 'c', 'a'>>>,
Expect<Equal<MyExclude<'a' | 'b' | 'c', 'a' | 'b'>, Exclude<'a' | 'b' | 'c', 'a' | 'b'>>>,
Expect<Equal<MyExclude<string | number | (() => void), Function>, Exclude<string | number | (() => void), Function>>>,
]
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Awaited
import { Equal, Expect } from '@type-challenges/utils'
type Awaited<T> = T extends Promise<infer R> ? R : never
type X = Promise<string>
type Y = Promise<{ field: number }>
type cases = [
Expect<Equal<Awaited<X>, string>>,
Expect<Equal<Awaited<Y>, { field: number }>>,
]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
If
import { Equal, Expect } from '@type-challenges/utils'
type If<C extends boolean, T, F> = C extends true ? T : F
type cases = [
Expect<Equal<If<true, 'a', 'b'>, 'a'>>,
Expect<Equal<If<false, 'a', 2>, 2>>,
]
// @ts-expect-error
type error = If<null, 'a', 'b'>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
Concat
import { Equal, Expect } from '@type-challenges/utils'
type Concat<T extends any[], U extends any[]> = [...T, ...U]
type cases = [
Expect<Equal<Concat<[], []>, []>>,
Expect<Equal<Concat<[], [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']>>,
]
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10