React JSX
- 使用文件后缀 (替代
.ts
); - 在你的
tsconfig.json
配置文件的compilerOptions
里设置选项"jsx": "react"
; - 在你的项目里为
JSX
和React
安装声明文件:npm i -D @types/react /react-dom
; - 导入
react
到你的.tsx
文件(import * as React from 'react'
)。
React 不但能渲染 HTML 标签(strings)也能渲染 React 组件(classes)。JavaScript 触发这些的原理是不同的(React.createElement('div')
vs React.createElement(MyComponent)
), 确定使用哪一种方式取决于首字母的大小写,foo
被认为是 HTML 标签,Foo
被认为是一个组件。
一个 HTML 标签 foo
被标记为 JSX.IntrinsicElements.foo
类型。在我们已经安装的文件 react-jsx.d.ts
中定义了所有主要标签的类型,如下是一部分示例:
函数式组件
你可以使用 React.FunctionComponent
接口定义函数组件:
type Props = {
foo: string;
};
const myComponent: React.FunctionComponent<Props> = props => {
return <span>{props.foo}</span>;
};
<MyComponent foo="bar" />;
类组件
根据组件的 props
属性对组件进行类型检查。这是以 JSX 如何转换做为蓝本,例如:属性成为 props
的组成部分。
react.d.ts
文件定义了 React.Component<Props,State>
,你应该使用自己所需的 Props
和 State
声明扩展它:
type Props = {
foo: string;
};
class MyComponent extends React.Component<Props, {}> {
render() {
return <span>{this.props.foo}</span>;
}
}
<MyComponent foo="bar" />;
React JSX Tip: 接收组件的实例
react 类型声明文件提供了 React.ReactElement<T>
,它可以让你通过传入 <T/>
,来注解类组件的实例化结果。
class MyAwesomeComponent extends React.Component {
render() {
return <div>Hello</div>;
}
}
const foo: React.ReactElement<MyAwesomeComponent> = <MyAwesomeComponent />; // Okay
const bar: React.ReactElement<MyAwesomeComponent> = <NotMyAwesomeComponent />; // Error!
当然,你可以将它用作函数参数的注解,甚至可以是 React 组件的 prop 成员。
类型 React.Component<Props>
是 React.ComponentClass<P>
与 React.StatelessComponent<P>
的组合,所以你可以接受一些可以用作 Props 类型和使用 JSX 渲染的组件。
const X: React.Component<Props> = foo; // from somewhere
// Render X with some props:
<X {...props} />;
React JSX Tip: 可渲染的接口
React 可以渲染一些像 JSX
或者是 string
的内容,这些被合并到类型 React.ReactNode
中,因此,当你接收可渲染的内容时,你可以使用它:
React JSX tip: 接收组件的接口
React 声明文件提供 React.ReactElement<T>
的接口,可以让你注解一个类组件实例化的返回值<T/>
,如:
class MyAwesomeComponent extends React.Component {
render() {
return <div>Hello</div>;
}
}
const foo: React.ReactElement<MyAwesomeComponent> = <MyAwesomeComponent />; // Okay
const bar: React.ReactElement<MyAwesomeComponent> = <NotMyAwesomeComponent />; // Error!
TIP
你也可以将其用做函数参数的注解,或者是 React 组件的 prop 注解。
React JSX tip: 接收可以做为 props 的组件,并且使用 JSX 渲染它
const X: React.Component<Props> = foo // 来自其他地方
// 渲染 X
<X {...props} />
它完全能按我们预期工作,如:
// 一个泛型组件
type SelectProps<T> = { items: T[] };
class Select<T> extends React.Component<SelectProps<T>, any> {}
// 使用
const Form = () => <Select<string> items={['a', 'b']} />;
泛型函数
一些像下面这样的正常工作:
function foo<T>(x: T): T {
return x;
}
然而不能使用箭头泛型函数:
解决办法:在泛型参数里使用 extends
来提示编译器,这是个泛型:
const foo = <T extends {}>(x: T) => x;
React Tip: 强类型的 Refs
基本上你在初始化一个变量时,使用 ref 和 null 的联合类型,并且在回调函数中初始化他:
class Example extends React.Component {
example() {
// ... something
}
render() {
return <div>Foo</div>;
}
}
exampleRef: Example | null = null;
render() {
return <Example ref={exampleRef => (this.exampleRef = exampleRef)} />;
}
}
使用原生元素时也一样:
input: HTMLInputElement | null = null;
render() {
return (
<input
ref={input => (this.input = input)}
value={this.props.value}
onChange={e => {
this.props.onChange(e.target.value);
}}
/>
);
}
focus() {
if (this.input != null) {
this.input.focus();
}
}
}
类型断言
- 在有状态组件中使用默认的 Props:你可以通过
null
操作符(这不是一个理想的方式,但是这是我能想到的最简单的最小代码解决方案)告诉 TypeScript 一个属性将会被外部提供(React)。
class Hello extends React.Component<{
/**
* @default 'TypeScript'
*/
compiler?: string;
framework: string;
}> {
static defaultProps = {
compiler: 'TypeScript'
};
render() {
const compiler = this.props.compiler!;
return (
<div>
<div>{compiler}</div>
<div>{this.props.framework}</div>
</div>
);
}
}
ReactDOM.render(
<Hello framework="React" />, // TypeScript React
);
原文: