我有以下帮助方法,该方法返回一个包装好的react组件。
export function wrapComponentInContext<T extends object = {}>(
Comp: React.FunctionComponent<T>,
props: T = {}) { // ERROR: Type '{}' is not assignable to type 'T'
const mockSetter = jest.fn(() => { });
const mockContext: ContextDefaultValue = ["context", mockSetter];
return (
<Provider value={mockContext}>
<Comp {...props}/>
</Provider>
);
}
如果不提供任何参数,我想默认为空对象。
这是一个更简单的example
所以看来一个空对象不是{}
类型,这很令人困惑。
为什么
答案 0 :(得分:1)
通用函数必须对传递给该函数的任何可能的T
有效。 T extends object
表示T
可以是任何对象类型,因此它可以是{ foo: string }
,而{}
对此类型不是有效的默认值。
type参数的默认类型与该参数的默认值没有任何关系。您可以使用显式类型参数且不使用默认值进行调用,从而在传入的默认值{}
和T
之间产生冲突。或者您可以省略默认值,并传入具有必需道具的组件:
declare function comp(o: { p: string }): void;
wrapComponentInContext(comp)
您可以使用类型断言来强制{}
进入T
:
export function wrapComponentInContext<T extends object = {}>(Comp: React.FunctionComponent<T>, props: T = {} as T) {
}
但是,这将使您暴露于上面我强调的潜在问题。您可以为{}
是有效默认值的组件添加专用的重载,尽管由于函数参数的相反性质,使其按预期工作需要一些条件类型:
declare function compOptional(o: { p?: string }): void;
declare function comp(o: { p: string }): void;
export function wrapComponentInContext<T>(Comp: React.FunctionComponent<T> & ({} extends T ? {} : "Provide default props as component requires some"))
export function wrapComponentInContext<T extends object>(Comp: React.FunctionComponent<T>, props: T)
export function wrapComponentInContext<T extends object = {}>(Comp: React.FunctionComponent<T>, props: T = {} as T) {
}
wrapComponentInContext(comp) // Type '(o: { p: string; }) => void' is not assignable to type '"Provide default props as component requires some"'.
wrapComponentInContext(compOptional)
wrapComponentInContext(comp, { p: "" })