我想使用 TypeScript 在 React 組件上強制執行屬性,但我的行為很奇怪。波紋管我只粘貼簡單的例子:
function FunctionalComponent(props: { color: string }) {
return <></>;
}
type ComponentWithName<I extends React.FunctionComponent<{ name: string } & React.ComponentProps<I>>> = I;
const component: ComponentWithName<typeof FunctionalComponent> = FunctionalComponent;
即使我宣告組件必須具有屬性名稱,上面的代碼也會通過。使用此代碼,我需要得到一個錯誤,因為FunctionalComponent不包含name屬性。
另一方面,這有效:
function FunctionalComponent(props: { color: string }) {
return <></>;
}
type ComponentWithName<I extends React.FunctionComponent<{ name: string }>> = I;
const component: ComponentWithName<typeof FunctionalComponent> = FunctionalComponent
這段代碼會拋出一個 TypeScript 錯誤,這正是我所需要的。但問題是,FunctionalComponent除非我手動將它們添加到React.FunctionComponent.
目標是強制組件具有“名稱”屬性,但允許具有更多附加(未指定)屬性。
我使用的是 TypeScript 4.4.4版和 React 17.0.2版
編輯:
真正的用例是這樣的:
function Component<
I extends
| React.ComponentClass<
{
onChange: (event: React.ChangeEvent) => void;
} & React.ComponentProps<I>
>
| React.ComponentType<
{
onChange: (event: React.ChangeEvent) => void;
} & React.ComponentProps<I>
>
>(
props: {
component?: I;
} & Omit<React.ComponentProps<I>, "onChange">
) {
const { component: Component, ...rest } = props;
const handleChange = () => {
//
};
return (
<div>
{Component ? (
<Component
{...(rest as React.ComponentProps<I>)}
onChange={handleChange}
/>
) : (
<input onChange={handleChange} />
)}
</div>
);
}
class ComponentClass extends React.Component<{
color: "blue" | "yellow";
}> {
render() {
return (
<input style={{color: this.props.color}} />
);
}
}
function ComponentFunction(props: { color: "blue" | "yellow" }) {
return <input style={{color: props.color}} />;
}
function App() {
return (
<>
<Component component={ComponentClass} color="blue" />
<Component component={ComponentFunction} color="blue" />
</>
);
}
該<Component component={ComponentClass} color="blue" />會拋出一個型別錯誤,但<Component component={ComponentFunction} color="blue" />沒有。我需要強制傳遞的組件具有onChange指定型別的屬性。
uj5u.com熱心網友回復:
我可能遺漏了一些東西,但是您是否只需要強制執行型別Props而不是創建型別化組件?
interface NameProps {
name: string;
}
type NamedComponent<T extends NameProps> = (props: T) => JSX.Element;
const notANamedComponent: NamedComponent<{ int: number }> // ...this will give you an error
const aNamedComponent: NamedComponent<{ int: number; name: string}> //OK
uj5u.com熱心網友回復:
問題是將額外的欄位傳遞給組件總是有效的,如果你想要求它做一些事情,它很難輸入。
例如,這是有效的代碼:
// from this context the argument will be called with an argument with both a and b properties
function takeF(f: (data: {a:string, b:number})=>any){}
// this function takes an object with an a property, but passing other properties would still be valid
function f(data: {a:string}){}
// this is allowed because passing an object with extra fields is still valid.
takeF(f)
您得到的誤差的原因{name: string}和{color:string}是因為這些有沒有重疊,所以打字稿不會給你的錯誤,所以解決的辦法是限制你一般什么實際需要。
declare function Component<
ComponentProps extends { onChange: (event: React.ChangeEvent) => void; }
>(
props: {
component?: React.ComponentClass<ComponentProps> | React.ComponentType<ComponentProps>;
} & Omit<ComponentProps, "onChange">
): any
這樣,如果組件沒有 onChange 則沒有重疊,并且您會得到您期望的錯誤,如果有額外的屬性,那很好,因為這些屬性已經被通用行為捕獲了。另請注意,這與@Marcus所說的基本相同,只是將泛型限制為您實際需要的內容。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/326543.html
