我正在尝试创建一个函数,该函数接收具有某些属性的对象,然后使用这些属性之一来生成结果的类型。
功能参数
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
,这是实际的对象输入。
答案 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>>
}
您的初始代码以供参考
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 } })