typescript 如何键入util函数,为该对象提供通用对象和部分默认值?

y1aodyip  于 2022-12-05  发布在  TypeScript
关注(0)|答案(1)|浏览(140)

我想输入一个泛型函数,它接受一个泛型对象datadefaultsdefaults应该是data的一部分。
以下是我目前所掌握的情况:

const setDefaults = <T extends Record<string, unknown>, U extends Partial<T>>(
  data: T | undefined,
  defaults: U,
) => {
  if (data) return data

  return defaults
}

type MyData = {
  id: number,
  roles: Array<string>,
}

let data: MyData | undefined

const { id, roles } = setDefaults(data, { roles: [] })

id的类型应为number | undefined,因为它没有提供默认值。
roles的类型应为Array<string>,因为它提供了默认值。
当前的解决方案使roles类型成为never[] | string[],使id成为any,这不是我想要的。

klsxnrf1

klsxnrf11#

要解决id和roles类型的问题,您可以使用TypeScript内置实用程序类型中的Required类型,使U中的所有属性都成为必需。这将导致id的类型为number(因为它在MyData中是必需的),而roles的类型为string[](因为它有默认值[])。以下是使用Required类型的代码的更新版本:

import { Required } from "utility-types"

const setDefaults = <T extends Record<string, unknown>, U extends Partial<T>>(
  data: T | undefined,
  defaults: Required<U>
) => {
  if (data) return data

  return defaults
}

type MyData = {
  id: number,
  roles: Array<string>,
}

let data: MyData | undefined

const { id, roles } = setDefaults(data, { roles: [] })

console.log(id) // number | undefined
console.log(roles) // string[]

您也可以使用... spread运算子来合并数据和预设值,然后传回结果对象,以稍微简化函数。这样可以让您避免使用if陈述式,并传回具有正确型别的单一对象。以下是范例:

import { Required } from "utility-types"

const setDefaults = <T extends Record<string, unknown>, U extends Partial<T>>(
  data: T | undefined,
  defaults: Required<U>
) => ({
  ...defaults,
  ...data,
})

type MyData = {
  id: number,
  roles: Array<string>,
}

let data: MyData | undefined

const { id, roles } = setDefaults(data, { roles: [] })

console.log(id) // number | undefined
console.log(roles) // string[]

相关问题