根据Typescript中输入对象的属性,使用键从函数返回对象

时间:2019-10-20 14:05:19

标签: javascript typescript

我正在尝试创建一个函数,该函数接收具有某些属性的对象,然后使用这些属性之一来生成结果的类型。

功能参数

interface Params<T> {
  entries?: { [key in T['entries']: string]: number }
  unit?: string
}

和结果

type Result<T> = { [key in T: string]: string }

结果中的T为Params['entries']

我设置了一个简单的typescript playground来显示我的尝试。

目前,如果您输入result.,则仅建议输入big|small作为默认值,而不建议a,这是实际的对象输入。

1 个答案:

答案 0 :(得分:1)

问题出在这里

generateUnitStrings = <O>(options?: Params<O>) // ---> the <O>

什么是O?这就是PickEntries<O> extends never返回true的原因。一种检查方法是这样做

const result = generateUnitStrings<{ entries: { a: number } }>({ entries: { a: 1 } })

您将看到它确实有效。自动补全正确提示'a'。原因是当您调用generateUnitStrings时,O{ entries: { a: number } }正确地切换了,并将其传递给Params,一切正常。

尝试一下(对我来说有点奇怪,但实际上有效!):

export const generateUnitStrings = <O extends Params<O>>(options?: O) => {
...

编辑

  

是的,但是现在您的解决方案仅在generateUnitStrings()具有参数的情况下建议使用某些东西,如果它使用空作为generateUnitStrings(),则不会自动建议默认参数small | big

提供默认的通用类型(在本例中为defaultParams类型)似乎可以完成工作

export const generateUnitStrings = <O extends Params<O> = typeof defaultParams>(options?: O) => {
  const entries = (options && options.entries) || defaultParams.entries
  const unit = (options && options.unit) || defaultParams.unit

  return Object.keys(entries).reduce(
    (acc, v) => ({ ...acc, [v]: `${entries[v as keyof typeof entries]}${unit}` }),
    {}
  ) as PickEntries<O> extends never ? Result<PickEntries<typeof defaultParams>> : Result<PickEntries<O>>
}

Playground

您的初始代码以供参考

type FilterProperties<T, P> = {
  [K in keyof T]: K extends P ? K : never
}[keyof T]
type PickEntries<T> = T[FilterProperties<T, 'entries'>]

interface Params<T> {
  entries?: { [K in keyof PickEntries<T>]: number }
  unit?: string
}

type Result<T> = { [P in keyof T]: string }

export const defaultParams = {
  entries: {
    small: 600,
    big: 1200,
  },
  unit: 'px',
}

export const generateUnitStrings = <O>(options?: Params<O>) => {
  const entries = (options && options.entries) || defaultParams.entries
  const unit = (options && options.unit) || defaultParams.unit

  return Object.keys(entries).reduce(
    (acc, v) => ({ ...acc, [v]: `${entries[v as keyof typeof entries]}${unit}` }),
    {}
  ) as PickEntries<O> extends never ? Result<PickEntries<typeof defaultParams>> : Result<PickEntries<O>>
}

const result = generateUnitStrings({ entries: { a: 1 } })