我试图了解在typescript中使用tsx文件来键入推断是否存在限制。
如果我创建无状态反应组件:
interface TestProps {
foo: string;
}
export const TestComp: React.StatelessComponent<TestProps> = x => {
return(<div>{foo}</div>);
};
然后在第二个tsx文件中尝试以下操作:
import { TestComp } from './TestComp';
const getProperties = function<P>(node: React.ReactElement<P>) : P {
return node.props
};
var props1 = getProperties(React.createElement(TestComp, { foo : 'bar' }));
var props2 = getProperties(<TestComp foo='bar' />);
props1将具有 TestProps 的推断类型,props2将具有任何的推断类型。
我的印象是最后两行相同。 Typescript是否认为第二次调用中的对象是React.ReactElement<any>
?
答案 0 :(得分:1)
这里只是一些语法混淆。你的箭头功能没有按照你的想法做到:
export const TestComp: React.StatelessComponent<TestProps> = x => {
return(<div>{foo}</div>);
};
已将x
标记为any
。此外,x
甚至不在函数中使用。你真正想要的是:
export const TestComp: React.StatelessComponent<TestProps> = (x: TestProps) => {
return(<div>{x.foo}</div>);
};
顺便说一下,关于箭头功能的快速文体说明:如果我不得不使用bind
,我通常只使用箭头功能。在这个简单的例子中,我实际上更喜欢使用普通函数,因为this
没有时髦的业务。
答案 1 :(得分:1)
这段代码
export const TestComp: React.StatelessComponent<TestProps> = x => {
return(<div>{foo}</div>);
};
使用在反应.d.ts中定义的接口:
interface StatelessComponent<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
...
}
这表明x
的推断类型为TestProps & { children?: ReactNode }
。这很好用,可以在VS Code的intellisense结果中看到。
然而,该函数的返回类型并不像我预期的那样<{em> ReactElement<TestProps>
,它是ReactElement<any>
。
通过比较,createElement定义为:
function createElement<P>(
type: SFC<P>,
props?: Attributes & P,
...children: ReactNode[]): SFCElement<P>;
,其中
type SFC<P = {}> = StatelessComponent<P>;
interface SFCElement<P> extends ReactElement<P> { }
调用React.createElement(TestComp, { foo : 'bar' })
允许来自TestProps
的{{1}}的通用参数一直冒泡到最终创建的元素中。
总结:通过明确地将TestComp
定义为TestComp
,我还将工厂函数中返回的元素定义为StatelessComponent<TestProps>
。删除此定义并将组件写为:
ReactElement<any>
或
export function TestComp(x: TestProps) {
...
}
提供Typescript less 信息并允许它推断出正确的类型,而不是强迫它使用错误的类型......