2017-08-16 22 views
2

我想了解是否有键入incript中使用tsx文件类型推断的限制。在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>有什么原因吗?

+1

经过进一步调查,如果我将TestComp定义为正常函数而不是箭头函数'export function TestComp(props:TestProps){...}' –

回答

1

迈克尔的回答指出了我的正确方向,因为它让我深入挖掘了React的.d.ts文件,但实际原因更为微妙。

的代码

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结果中看到。

然而,该功能的返回类型不是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>我也从工厂用作ReactElement<any>定义返回的元素。删除此定义,并写成分为:

export function TestComp(x: TestProps) { 
    ... 
} 

export const TestComp = (x: TestProps) => { 
    .... 
} 

给人打字稿信息,并允许它来推断正确的类型,而不是强迫它用错了一个...

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正在进行。

+0

是的,函数中缺少的'x'是一个错字,因为我试图简化我的真实代码,直到问题的一个例子。由于许多原因(主要是改进酶/笑话测试快照中的组件名称),我决定转移到正常函数,但是来自C#背景,我更喜欢箭头函数处理this这种方式,因为它是更接近我的心智模式...... –