typescript 使用jsx语法

(1)修改tsconfig.json
	"jsx": "preserve",	有三种模式
	
	preserve:生成代码中会保留JSX以供后续的转换操作使用(比如:Babel).另外,输出文件会带有.jsx扩展名。 
	react:会生成React.createElement,在使用前不需要再进行转换操作了,输出文件的扩展名为.js。 
	react-native:相当于preserve,它也保留了所有的JSX,但是输出文件的扩展名是.js
	
	模式 			输入 		输出 						输出文件扩展名
	preserve 		<div /> 	<div /> 					.jsx
	react 			<div /> 	React.createElement("div") 	.js
	react-native 	<div /> 	<div /> 					.js

(2)创建.tsx后缀文件
	因为jsx语法尖括号原因,<>方式的类型断言需要改写成as语法

(3)tsc语法
	1、固有元素
	    (1)对于React,固有元素会生成字符串(React.createElement("div")),然而由你自定义的组件却不会生成(React.createElement(MyComponent))。
	    (2)传入JSX元素里的属性类型的查找方式不同。 固有元素属性本身就支持,然而自定义的组件会自己去指定它们具有哪个属性。
	    (3)固有元素总是以一个小写字母开头,基于值的元素总是以一个大写字母开头。

		固有元素使用特殊的接口JSX.IntrinsicElements来查找,如果这个接口存在,固有元素的名字需要在JSX.IntrinsicElements接口的属性里查找。
			declare namespace JSX {
			    interface IntrinsicElements {
			        foo: any
			        也可以使用索引前面捕获所有
			        	[index: string]: any;
			    }
			}
			<foo />; // 正确
			<bar />; // 错误
			
	2、基于值的元素(无状态函数组件(SFC),类组件)
		基于值的元素会简单的在它所在的作用域里按标识符查找。
			import MyComponent from "./myComponent";
			<MyComponent />; // 正确
			<SomeOtherComponent />; // 错误
		
		无状态组件:
			interface FooProp {
			    className: string;
			    X: number;
			    Y: number;
			}
			function ComponentFoo(prop: FooProp) {
			    return <div className={prop.className} />;
			}
			let mytag = <ComponentFoo className={"title"} X={1} Y={2} />;
			
			由于无状态函数组件是简单的JavaScript函数,所以我们还可以利用函数重载。
				interface ClickableProps {
				    children: JSX.Element[] | JSX.Element
				}
				
				interface HomeProps extends ClickableProps {
				    home: JSX.Element;
				}
				
				interface SideProps extends ClickableProps {
				    side: JSX.Element | string;
				}
				
				function MainButton(prop: HomeProps): JSX.Element;
				function MainButton(prop: SideProps): JSX.Element {
				    ...
				}
				
	 
	 类组件:
		declare namespace JSX {
		    interface ElementClass {
		        render: any;	限制JSX的类型以符合相应的接口。
		    }
		}
		class MyComponent {
		    render() { }
		}
		工厂函数的实例类型为函数返回值类型,即函数若要充当类,必须使用工厂函数返回类型才相同
		function MyFactoryFunction() {
		    return { render: () => { } }
		}
		<MyComponent />;                // 正确
		<MyFactoryFunction />;          // 正确
		 
		class NotAValidComponent { }    // 缺少 render
		function NotAValidFactoryFunction() {
		    return {};                  // 缺少 render
		}
		<NotAValidComponent />;         // 错误
		<NotAValidFactoryFunction />;   // 错误	
			
			其中:类类型和工厂函数返回类型
				class MyComponent {
				    render() {}
				}
				
				// 使用构造签名
				var myComponent = new MyComponent();
				
				// 元素类的类型:MyComponent
				// 元素实例的类型: { render: () => void }
				
				function MyFactoryFunction() {
				    return {
				    render: () => {
				    }
				    }
				}
				
				// 使用调用签名
				var myComponent = MyFactoryFunction();
				
				// 元素类的类型:FactoryFunction
				// 元素实例的类型: { render: () => void }
	
	3、类型检查
		固有属性:
			
			不合法标识符未被定义但出现时不会被当作一个错误
			declare namespace JSX {
			    interface IntrinsicElements {
			        foo2: { requiredProp: string; optionalProp?: number }
			    }
			}
			<foo2 requiredProp="bar" />;                    // 正确
			<foo2 requiredProp="bar" optionalProp={0} />;   // 正确
			<foo2 />;                                       // 错误, 缺少 requiredProp
			<foo2 requiredProp={0} />;                      // 错误, requiredProp 应该是字符串
			<foo2 requiredProp="bar" unknownProp />;        // 错误, unknownProp 不存在
			<foo2 requiredProp="bar" some-unknown-prop />;  // 正确, `some-unknown-prop`不是个合法的标识符
	
		基于值的元素:
			如果未指定JSX.ElementAttributesProperty,那么将使用类元素构造函数或(SFC调用的第一个参数)的类型。
			
			declare namespace JSX {
			    interface ElementAttributesProperty {
			        props: any; 指定用来使用的属性名,只能有一个
			    }
			}
			
			class MyComponent {
			    在元素实例类型上指定属性
			    props!: {	!加了赋值断言,避免在赋值前使用
			        foo?: string
			        num: number
			    }
			}
			
			
			// `MyComponent`的元素属性类型为`{foo?: string}`
			<MyComponent foo="bar" num={2} />

(4)子孙类型检查
	使用children关键字
	
	如不特殊指定子孙的类型,我们将使用React typings里的默认类型。
	declare namespace JSX {
	    interface ElementChildrenAttribute {
	    children: {};  // specify children name to use
	    }
	}
	
	在React中:
		
		interface PropsType {
		    children: JSX.Element
		    name: string
		}
		
		class Component extends React.Component<PropsType, {}> {
		    render() {
		        return (
		            <h2>
		            {this.props.children}
		            </h2>
		        )
		    }
		}
		
		// OK
		<Component>
		    <h1>Hello World</h1>
		</Component>
		
		// Error: children is of type JSX.Element not array of JSX.Element
		<Component>
		    <h1>Hello World</h1>
		    <h2>Hello World</h2>
		</Component>
		
		// Error: children is of type JSX.Element not array of JSX.Element or string.
		<Component>
		    <h1>Hello</h1>
		    World
		</Component>

(5)JSX结果类型
	默认地JSX表达式结果的类型为any,你可以自定义这个类型,通过指定JSX.Element接口,然而,不能够从接口里检索元素,属性或JSX的子元素的类型信息,它是一个黑盒。

猜你喜欢

转载自blog.csdn.net/weixin_43294560/article/details/114284602