TypeScript 类型体操 01

发现一个好玩的开源项目: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] 获取成员的类型
Back to Top