tsx 文件中的通用类型解析
Generic type resolution in tsx files
我想了解在打字稿中使用 tsx 文件进行类型推断是否存在限制。
如果我创建一个无状态的 React 组件:
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 的推断类型为 any.
我的印象是最后两行是等价的。 Typescript 认为第二次调用中的对象是 React.ReactElement<any>
是有原因的吗?
这里只是一些语法错误。你的箭头函数没有按照你的想法去做:
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
没有任何时髦的事情在进行。
Michael 的回答为我指明了正确的方向,因为它让我深入研究了 React 的 .d.ts 文件,但实际原因更为微妙。
这段代码
export const TestComp: React.StatelessComponent<TestProps> = x => {
return(<div>{foo}</div>);
};
使用在 react 中定义的接口。d.ts as:
interface StatelessComponent<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
...
}
这表明 x
将具有 TestProps & { children?: ReactNode }
的推断类型。这工作正常,可以在 VS Code 的智能感知结果中看到。
然而,那个函数的return类型并不是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
的通用参数从 TestComp
一直冒泡到最终创建的元素。
总结一下:通过将 TestComp
显式定义为 StatelessComponent<TestProps>
,我还将工厂函数中的 returned 元素定义为 ReactElement<any>
。删除此定义并将组件编写为:
export function TestComp(x: TestProps) {
...
}
或
export const TestComp = (x: TestProps) => {
....
}
给 Typescript 更少 信息并允许它推断正确的类型而不是强迫它使用错误的类型...
我想了解在打字稿中使用 tsx 文件进行类型推断是否存在限制。
如果我创建一个无状态的 React 组件:
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 的推断类型为 any.
我的印象是最后两行是等价的。 Typescript 认为第二次调用中的对象是 React.ReactElement<any>
是有原因的吗?
这里只是一些语法错误。你的箭头函数没有按照你的想法去做:
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
没有任何时髦的事情在进行。
Michael 的回答为我指明了正确的方向,因为它让我深入研究了 React 的 .d.ts 文件,但实际原因更为微妙。
这段代码
export const TestComp: React.StatelessComponent<TestProps> = x => {
return(<div>{foo}</div>);
};
使用在 react 中定义的接口。d.ts as:
interface StatelessComponent<P = {}> {
(props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
...
}
这表明 x
将具有 TestProps & { children?: ReactNode }
的推断类型。这工作正常,可以在 VS Code 的智能感知结果中看到。
然而,那个函数的return类型并不是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
的通用参数从 TestComp
一直冒泡到最终创建的元素。
总结一下:通过将 TestComp
显式定义为 StatelessComponent<TestProps>
,我还将工厂函数中的 returned 元素定义为 ReactElement<any>
。删除此定义并将组件编写为:
export function TestComp(x: TestProps) {
...
}
或
export const TestComp = (x: TestProps) => {
....
}
给 Typescript 更少 信息并允许它推断正确的类型而不是强迫它使用错误的类型...