-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[翻译] TypeScript 和 JSX 搞基的事 #3
Comments
棒棒的 |
点赞~ |
值得关注 |
看的我热血沸腾。。。 |
请教一下,楼主有没有关于typescript和react的代码组织结构方面的文章。比如说我在项目开发中要用redux、react-router,要引用react库、jquery库,这些库想编译成一个js文件,还有若干公共React组件,也会分类编译成几个js文件,还有一些页面react的js文件,是一对一的编译。使用过多个解决方案,始终没有完美的,也可能是我技术不够,比如tsc原生编译的js文件中require方法不能在浏览器中用,用gulp和gulp-typescript,不识别模块,使用browserify也不行,要再加上babel,那不用ts也能转译react语法了,感觉ts好像没用上。另外ts用的库都在typings里,还要保证翻译后的js或jsx被其他的构建系统和转换工具所识别,而且网上的教程多是如何把所有的tsx编译成一个js,我不可能那么做啊,那样的话,js文件得多大啊!好折腾,每个方案都只是差一点,就是不能实现。 |
非常感谢楼主的辛苦工作,我会仔细学习的,如果有什么不清楚的地方再向你请教。说句题外话,你能给个思路点拨一下,就非常好了,没想到还专门给写了代码,不胜感激哈! |
真是棒!TypeScript + React 才是未来啊、 |
我表示,我懵逼!tsx让我要先学两种写法才能看懂ant design mobile的代码...不禁留下了眼泪... |
楼主,请教一下 在tsconfig.json中配置的paths在vscode中不识别 但是ts编译能通过 怎么解决啊。。 |
为什么这里的 |
还有,这里的
new 是什么意思, React 中并不需要 new 啊。作为类我知道新建实例需要new,但是react中并不需要吧,如果说MyComponent 并不是react中的,那为什么里面会有render函数? |
好文!收藏!!! |
我能不能不改jsx后缀,在项目中同时使用jsx和tsx,因为项目是很多人一起做的,我只负责了一部分,这种情况我使用tsx不能影响其他人的,这样我先拿自己的部分做实验,然后推广 |
请问楼主,怎么像使用jsx一样使用defaultProps给组件的props设置默认值呢? |
any一把梭 |
对 JSX 的支持已经在 TypeScript 官方落地了!非常感谢 Ryan Cavanaugh 和 François de Campredon 的大力推动。在这篇文章中,笔者打算跟大家探索一下如何把 JSX 和 TypeScript 的第一特性——静态类型检查完美结合使用。
发展历史
当我们开始在 AssureSign 项目中实验性地使用 React 的时候,也开始在使用 TypeScript 了。然而当我们碰到 JSX 的时候,一道石墙突然在我们面前挡道。在 Github 中已经有一个历史悠久的 Issue 去反映这个问题,然而一直没有得出实质性的解决方案,或者干脆让你“不要使用 JSX”了。这对我来说不可接受,所以我用了一点黑魔法来解决这个问题。虽然可以玩起来,但这个方法太挫了,并且没有类型检查。François de Campredon 后来创建了一个 jsx-typescript 的项目来证明其实 TypeScript 是可以支持 JSX 的。然后,很突然,会得到 TypeScript 官方支持的消息不胫而走。三个月后,它就真的支持了。
安装
目前 JSX 还没有稳定版本,所以你需要去拉取最新代码。JSX 已经在 TypeScript 1.6 以上版本支持。
基础使用
使用 JSX 之前,你需要做两件事情:
.tsx
作为扩展名jsx
选项TypeScript 发布了两种 JSX 的工作模式:
preserve
模式和react
模式。这两个模式只影响编译策略。preserve
模式会保留 JSX 文件,以便日后进一步被 babel 使用,输出的文件是.jsx
格式的。而react
模式则会直接编译成React.createElement
,在使用之前就不需要再做 JSX 转换了,输出的文件是.js
格式的。你可以在命令行中使用
--jsx
参数或者在 tsconfig.json 中指定工作模式。注意,编译生成的代码中,
React
关键字是硬编码的,所以要保证全局变量中的 React 可用,并且 R 是大写的,react
就不行了。as
运算符由于 TypeScript 使用尖括号做类型声明,那么在编译的时候,类型声明会和
JSX
的语法冲突。比如以下代码:这个代码是准备创建一个 JSX 元素,还是想要声明
bar
变量是foo
类型的?为了让这个问题简化,.tsx
文件里不支持尖括号类型声明语法。所以如果上面的代码是在.tsx
文件里的话,表示的是创建了一个 JSX 元素,而如果在.ts
文件里,就会报错。为了弥补.tsx
文件中类型声明语法的缺失,添加了一个新的类型声明操作符:as
。as
操作符在.ts
文件和.tsx
文件中都是可用的。类型检查
要是没有类型检查,JSX 和 TypeScript 搞基有什么意义?多亏有了完整的类型检查,世界变得精彩纷呈。
首先,要区别内置元素和自定义元素。给定一个 JSX 表达式
<expr />
,这个expr
到底该对应环境里的一个内置元素(比如 DOM 环境下的 div 或者 span)还是应该对应一个自己写的自定义组件?区分这单很重要,因为:React.createComponent('div')
,而自定义元素则不是:React.createElement(MyComponent)
对于这两者,TypeScript 和 React 使用同样的区分方式:内置元素的标签以小写字母开头,自定义元素的标签使用大写字母开头。
内置元素
内置元素会在接口
JSX.InterinsicElements
中定义。默认情况下,如果这个接口并没有定义,那么所有的内置元素都不会进行类型检查。然而,如果你定义了这个接口,那么内置元素将会使用在接口属性中定义的类型。在上述示例中,
foo
可以通过类型检查但是bar
不行。因为bar
在内置元素接口属性中没有定义。注意:你也可以在
JSX.IntrinsicElements
接口中定义一个字符串索引器来匹配任意的内置元素自定义元素
自定义元素可以简单地通过标识符来查找到。
我们是可以限制自定义组件的类型的。然而,为了说明白,我们先要介绍两个概念:_组件类类型(Element Class Type)和_组件实例类型(Element Instance Type)。
组件类类型很简单,对于
<Expr>
组件,其类类型就是Expr
的类型。所以在上面的例子中,如果MyCompoent
是一个 ES6 的类,那么<MyComponent>
的类类型就是这个类的类型。如果MyComponent
是一个工厂方法,那么<MyCompoent>
的类类型就是这个方法的类型。一旦元素类类型确定了,元素的实例类型就由类的调用签名和构造签名共同决定。在看上述例子,如果
MyComponent
是一个 ES6 的类,那么实例类型就是这个类的实例的类型,如果是个工厂方法,实例类型则是这个方法的返回值。是不是有点绕?我们来看看下面这个例子:现在组件实例类型是一个有趣的类型,它要求满足
JSX.ElementClass
的接口,否则将会报错。默认情况下,JSX.ElementClass
就是{}
,不过我们是可以人为增加限制。译者注:
JSX.ElementClass
同样在 React 的 DefinitelyTyped 中定义好了,大家通过 tsd 或者 nuget 可以下载下来使用属性类型检查
做属性的类型检查,第一步就是要确定_元素属性类型_。对于内置元素和自定义元素,确定方式有一些区别。
对于内置组件,组件属性类型就是
JSX.IntrinsicElements
上的属性类型。对于自定义组件,情况复杂一点点。它的类型是之前讨论的_组件实例类型_的一个属性决定的。你问我是哪个属性?哈哈,你可以自己决定!在
JSX.ElementAttributesProperty
上定义唯一一个属性,这个属性就是决定自定义组件属性类型的属性。(译者:好绕,还是看示例)上面的例子可以明显看到,元素属性类型就是用于对 JAX 的元素做类型检查的。支持可选和必选属性。
_注意:如果一个属性名称不是一个合法的 JS 标识符(比如
data-_
属性),那么这个属性在进行类型检查的时候不会认为是错误,而是直接跳过。*属性集也是支持的:
JSX 的类型
好了,现在我们可以写 JSX 并且有了元素和属性的类型检查,但是 JSX 本身的类型是什么呢?默认来说,JSX 的类型是
any
。你可以通过JSX.Element
接口自定义这个类型。然而,我们从这个接口是不可能知道元素、元素的属性或者子节点的类型信息的。这是个黑盒。内嵌 TypeScript
JSX 在 Javascript 里允许通过花括号
{ }
内嵌 JavaScript 代码。JSX 在 TypeScript 里同样允许你这样做,只不过是内嵌 TypeScript 代码。这就意味着这些 JSX 内嵌的 TypeScript 代码同样支持转译功能以及类型检查。上面的代码会报错,因为你不能使用字符串来除以一个数值。当使用
preserve
模式的时候,输出是这样的:React 集成
TypeScript 对 JSX 的支持的设计是不考虑其使用方式的。然而,React 始终是主要的使用方。我年初做过一个关于集成 React 和 TypeScript 的演讲。很多观点如今依然适用。React 的 DefiniteTyped 仓库的最近更新中集成了
JSX.IntrinsicElements
和JSX.ElementAttributeProperty
的概念。更多资源
这篇文章中的很多信息都来自 TypeScript 的 Issue #3203。不过,这个讨论已经持续了很长时间并且扩散到很多个地方。我调了几个个人认为值得深挖的:
as
operator microsoft/TypeScript#3564The text was updated successfully, but these errors were encountered: