Skip to content
On this page

pick

https://github.com/type-challenges/type-challenges/blob/main/questions/00004-easy-pick/README.md

问题

实现 TS 内置的 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,
}

解答

ts
// ============= Test Cases =============
import type { Equal, Expect } from './test-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
}


// ============= Your Code Here =============
type MyPick<T, K extends keyof T> = {
  [P in K]: T[P]
}

说明

  • keyof: 取 interface 的键后保存为联合类型
ts
interface userInfo {
  name: string
  age: number
}
type keyofValue = keyof userInfo
// keyofValue = "name" | "age"
  • in: 取联合类型的值,主要用于数组和对象的构建。切记不要用于 interface, 否则会报错
ts
type name = 'firstname' | 'lastname'
type TName = {
  [key in name]: string
}
// TName = { firstname: string, lastname: string }

用于实际开发,举个例子

ts
function getValue(o:object, key: string){
  return o[key]
}
const obj1 = { name: '张三', age: 18 }
const values = getValue(obj1, 'name')

这样写丧失了 ts 的优势:

  • 无法确定返回值类型
  • 无法对 key 进行约束

应该这样定义:

ts
function getValue<T extends Object,K extends keyof T>(o: T,key: K): T[K] {
  return o[key]
}
const obj1 = { name: '张三', age: 18}
const values = getValue(obj1, 'name')
// 如果第二个参数不是 obj1 中的参数就会报错