发现一个好玩的开源项目:type-challenges,在上面可以做一些TypeScript类型相关的题目,这里记录一下自己的学习。
00004-easy-pick
/* _____________ Your Code Here _____________ */
type MyPick<T, K extends keyof T> = { [Key in K]: T[Key] }
/* _____________ Test Cases _____________ */
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
}
00007-easy-readonly
/* _____________ Your Code Here _____________ */
type MyReadonly<T> = { readonly [Key in keyof T]: T[Key] }
/* _____________ Test Cases _____________ */
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
}
}
00011-easy-tuple-to-object
/* _____________ Your Code Here _____________ */
type TupleToObject<T> = T extends readonly string[] ? { [Key in T[number]]: Key } : error
/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
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' }>>,
]
// @ts-expect-error
type error = TupleToObject<[[1, 2], {}]>
这里很多人的答案是:
type TupleToObject<T extends readonly any[]> = { [k in T[number]]: k };
但是其实是不对的,因为这样没有满足最后一个判断条件:type error = TupleToObject<[[1, 2], {}]>
00014-easy-first
/* _____________ Your Code Here _____________ */
type First<T extends any[]> = T extends [infer First, ... any[]] ? First : never
/* _____________ Test Cases _____________ */
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' }>,
]
00018-easy-tuple-length
/* _____________ Your Code Here _____________ */
type Length<T extends readonly any[]> = T["length"]
/* _____________ Test Cases _____________ */
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'>,
]
今天先搞这五道题吧,总结一下收获:
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] // tuple的类型是一个可变数组 string[]
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const // tuple的类型是:readonly ["tesla", "model 3", "model X", "model Y"]
// 00011 和 00018 两道题能够成立的前提是 数组后面加了 as const 。
type tuple_items = typeof tuple[number]; //"tesla" | "model 3" | "model X" | "model Y"
type todo_items = keyof Todo;
type a = "title" extends keyof Todo ? true : false; // a == true
type b = "tesla" extends typeof tuple[number] ? true : false; // b == true
// 数组可以通过 T[number] 获取成员
// 类型通过 keyof T 获取成员, T[Key] 获取成员的类型