英文:
Typescript infer rest type of generic object type
问题
我正在为类似于React的函数组件编写一个部分函数。它接受一个名为 props
的参数,然后填充props
的特定键。例如,部分函数 foo
将属性 bar
的值填充到新组件中。
然而,TypeScript 编译器报错:
'Omit<T, "bar"> & { bar: number; }' 可分配给类型 'T' 的约束,但 'T' 可能会实例化为具有不同约束的不同子类型 '{ bar: number; }'
问题与这个问题非常相似,它使用infer
来处理参数列表。但是,我没有找到对象版本,而是找到了这个GitHub问题,其中建议使用Omit
。然而,Omit
对于泛型不起作用。
一个小例子来说明问题:
function func<T extends {foo: number}>(param: Omit<T, 'foo'>): T {
return {...param, foo: 3};
}
'Omit<T, "foo"> & { foo: number; }' 可分配给类型 'T' 的约束,但 'T' 可能会实例化为具有不同约束的不同子类型 '{ foo: number; }'
我还检查了一个解释这个错误的答案,但仍然无法理解。
如何使部分函数的类型签名正常工作?
英文:
I am writing a partial function for react-alike functional components. It accepts a single parameter props
, then fill a specific key of the props. For example, the partial function foo
fills value of prop bar
to the new component.
function foo<T extends {bar: number}>(functionalComponent: (props: T) => JSX.Element) {
return (props: Omit<T, 'bar'>) => {
return functionalComponent({...props, bar: 3});
}
}
However, typescript compiler complains:
> 'Omit<T, "bar"> & { bar: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ bar: number; }'
The problem is very similar to this one, which uses infer
for a parameter list. However, I didn't find an object version, instead I found this github issue, which suggests using Omit
. However, Omit
does not work for the generic.
A tiny example to illustrate the problem:
function func<T extends {foo: number}>(param: Omit<T, 'foo'>): T {
return {...param, foo: 3};
}
> 'Omit<T, "foo"> & { foo: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ foo: number; }'
I also checked an answer that explains this error, but still can't get the point.
How can I make the partial function type signature work?
答案1
得分: 1
Typescript 无法确定在 Omit
中还有未解析的泛型类型参数时会发生什么。要使此类型检查通过,我们可以在 functionalComponent
的 props
中添加一个与 Omit<T, 'bar'> & {bar: number}
的联合类型。虽然这似乎与 T
相同,但它的包含将允许 TypeScript 将包装组件的属性分配给功能组件的属性。当 T
解析时,T
和 Omit<T, 'bar'> & {bar: number}
将解析为相同的有效类型,因此它不应对调用站点产生影响:
type BaseProps = { bar: number }
function foo<T extends BaseProps>(
functionalComponent: (props: T | Omit<T, 'bar'> & BaseProps) => JSX.Element
) {
return (props: Omit<T, 'bar'>) => {
return functionalComponent({ ...props, bar: 3 });
}
}
英文:
Typescript can't follow what will happen with the Omit
as long as it still has an unresolved generic type parameter in it. What we could do to get this to type check is to add a union with Omit<T, 'bar'> & {bar: number}
to props
of functionalComponent
. While this seems the same as T
, it's inclusion will let typescript assign the wrapped component props to the functional component props. When T
is resolved, T
and Omit<T, 'bar'> & {bar: number}
will resolve to the same effective type, so it should have no impact to the call site:
type BaseProps ={bar: number}
function foo<T extends BaseProps>(functionalComponent: (props:
| T
| Omit<T, 'bar'> & BaseProps ) => JSX.Element) {
return (props: Omit<T, 'bar'>) => {
return functionalComponent({...props, bar: 3});
}
}
答案2
得分: 0
我找到了一个暴力解决方法:使用as
关键字。不确定是否存在更好的解决方案,所以我将它保留为未解决的。
function func<T extends {foo: number}>(param: Omit<T, 'foo'>): T {
return {...param, foo: 3} as T;
}
英文:
I found a brute-force workaround: using the as
keyword. Not sure if there exists a better solution, so I'll leave it unresolved.
function func<T extends {foo: number}>(param: Omit<T, 'foo'>): T {
return {...param, foo: 3} as T;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论