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 更少 信息并允许它推断正确的类型而不是强迫它使用错误的类型...