确实,TypeScript 手册的 JSX 部分是一个很好的资源 https://www.typescriptlang.org/docs/handbook/jsx.html;对于那些还没有看过的人,请检查一下。
如果你想tsc
要编译 JSX,您需要执行以下操作(极其广泛的概述):
- 声明
IntrinsicElements
接口/类型JSX
命名空间(启用类型安全)。
- 创建一个 JSX 工厂函数。
- 配置您的消费应用程序tsconfig to use
"react"
代码生成并指向您的 JSX Factory(使用"jsxFactory"
选项)。
- 将 JSX 工厂函数导入到.tsx file.
下面对此进行更深入的研究。还,您可能想查看存储库 https://github.com/ConnorJamesLow/texsaur或者可能一个工作示例/游乐场 https://www.typescriptlang.org/play?target=99#code/PQKgsAUABCUAICsDOAPKyWRsSw9QB4AnAUwDMTSA7AYxKgBsBLAIwF4AiAEQHkBZDlGAA+SJAAmJGgwCGpKFRkBbEkgAOMulABSAZQAaUAN5YoZ-ABUAFvVIAXAK5EqUOwE819APZkoXpzoGUABimnZeRG6mZu6eUACiDCQqVHZQbFAAEhZ8ADKJySSpANxi0GZCwFAAkqlETFRITDQFKXZ8MmpQAOZEMixIUDIMDK42UEh2MlTicuJZObmuMt2DDWP0FrpQvHyMrAB00VANdpRkmvS1dvWNza1FdoMkKGczg9e3TS1JbR1dRigAF8ysdLOMyF4Rl4AO4NbpDeQ0ByTLxKVweVQAGgUXjSGiIaR8UC2AHJBgBrKiwlx6QyKFTqS4ALmOsSudQa3weqX+6WMxwqUAA2gBpE4uCkkNzE7J5Hl2CwrAByyhI-wAusyBeUhXqRRTtZNbt0tUMqFFdXqQVabWzMSSVvypTLfHSDp8ufdfo8kKUIMdTudLlAAMJotReKiPHX6swACjURC8nkJTFUAH5tYDhS6jTd4Wbpm5gTiaFYmAxxNQs1BlV5JMKNQBKbX1yTHG12iBkBy0OxMKPoVAECxQF5vcSDd1KhEZGcrYTxqbdbUWHEyOwFlgOM5IbMG6X5k1Fi3AqAAHwUDhGOIO9-LlerRTbDZITdbgX0BwVkF7-cHFwMGXFZtXdcMlEjaNUg3Ld6h3PdtQABTkNUziIJACHZYkV2ES9r1vKB7wOR8q2oV9GxbCiSD-PsaAHIdgJXMCDAOWd8PAiMo0eWDt13VQD1zI8JgLKhTW1YtzyvKgbwYO8HwrMiXzrN8P1jComF8ZdMRwp02H0qBSX-ejANJZt1P1ewnBcFd403Pi9ygDMM2MIEy0U58qGbf0hRtIV2UdOcMU8XTuh8ioaCjSZxx9VJtTlfJYsVFU1X+YVZw1flxC8ZE2hI0hNxIBUQO6byyiFfAAEEkCaboXHs+D+P3Y4kjSJROn5Oy4NYJqnJcowgTKq1WqgJMU21F0cJ03x2rUcKzEhIgoETZMumJeMeBYBApDsA4XSQeNZvMmRBmLZtzJMAMrQqqp4lePp6KgAA3YYHAEwUKjGroMi+g5wl0UTunjIa4ygSLGjSF6GDe-lZuFL7MpO803HmvVwei4sACVyEoIotAyEgkqGU6LVRoVNOW7DfCxnHqDoeHVsy-SMlJPtJDIBoSHEMyLNByooGqoYoAuEYWE0CleOSNQ0nCCYSDSaYhm6hCSFZa640JwpUgOJB5cq5X+JWlMcSht6QbjIEYt13nQZpig6ffBH+VNkgyYqPz3fKip8E6TwZjBjzqGORblpG0j5mJcPqAuj6zAp7SQt8cP0gM8lAZ5y6+YqTW8oaaMiAsCcoAAagycO3f1cGBxk13Y+BOv48qog+jcA4mCQJuW-jcPzptjWkoOX2inEeNiJ7iu0ajau3onj39Rzx5B7UP3xFDDzu4882zDnqArOcGKtbsf1u2MhiXCQ+F40BFhocJYEDxvpw7GPeFgRjq095cAhxCYJ7hCMR+hIgQEGAD-P+kBuwvSWoTfkBAL5iSgIAuwnA3AyA4MIEB8DujCH9JAKBUAwGwMIUwcQnBIReHQZkQmDAvBfgAITGEJsA0Bv8cFlGyrlReLAGytyHjMNeT54xgObEAA.
JSX 命名空间
在这里,您告诉 TypeScript 如何解释您的 JSX 代码。您至少需要声明IntrinsicElements
,但是您可以声明其他类型,这些类型将为您提供更好的类型提示、启用组件功能,并通常改进/调整 TypeScript 对 JSX 的理解方式。
以下是 JSX 命名空间的声明示例:
/// <reference lib="DOM" />
declare namespace JSX {
// The return type of our JSX Factory: this could be anything
type Element = HTMLElement;
// IntrinsicElementMap grabs all the standard HTML tags in the TS DOM lib.
interface IntrinsicElements extends IntrinsicElementMap { }
// The following are custom types, not part of TS's known JSX namespace:
type IntrinsicElementMap = {
[K in keyof HTMLElementTagNameMap]: {
[k: string]: any
}
}
interface Component {
(properties?: { [key: string]: any }, children?: Node[]): Node
}
}
一些注意事项:
- 如果您打算与
HTMLElement
s and Node
是,DOM 库 (lib.dom.d.ts)是获得更好的类型检查的重要资源。在此示例中,我使用它来将所有真实的 HTML 标记声明为有效的内部元素。您可以进一步扩展它,例如预加载EventHandler
s like onclick
via GlobalEventHandlers
.
-
Element
是 TypeScript 在 JSX 命名空间中查找的另一种类型。这是可选的(默认为any
)。使用它来指定工厂函数的返回类型。
- 我们可以使用此定义创建一个简单的基于函数的组件(我已经使用
Component
界面。
- 对于类组件,我们需要声明
JSX.ElementClass
界面。看here https://www.typescriptlang.org/docs/handbook/jsx.html#class-component更多细节。
JSX 工厂函数
The JSX
命名空间帮助我们定义如何在代码中使用 JSX,但我们仍然需要实现一个可以处理由tsc
。我们的工厂函数应该遵循以下形式(tag: string, properties: { [k: string]: any }, ...children: any[]): any
,或更具体的东西。这是一个启用功能组件的示例(注意,它又大又丑):
function jsx(tag: JSX.Tag | JSX.Component,
attributes: { [key: string]: any } | null,
...children: Node[])
{
if (typeof tag === 'function') {
return tag(attributes ?? {}, children);
}
type Tag = typeof tag;
const element: HTMLElementTagNameMap[Tag] = document.createElement(tag);
// Assign attributes:
let map = (attributes ?? {});
let prop: keyof typeof map;
for (prop of (Object.keys(map) as any)) {
// Extract values:
prop = prop.toString();
const value = map[prop] as any;
const anyReference = element as any;
if (typeof anyReference[prop] === 'undefined') {
// As a fallback, attempt to set an attribute:
element.setAttribute(prop, value);
} else {
anyReference[prop] = value;
}
}
// append children
for (let child of children) {
if (typeof child === 'string') {
element.innerText += child;
continue;
}
if (Array.isArray(child)) {
element.append(...child);
continue;
}
element.appendChild(child);
}
return element;
}
TSX 和 tsconfig
现在,剩下的就是使用我们的jsx
功能。我们的 tsconfig 至少应该配置以下内容:
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "jsx",
}
}
现在,我们可以在任何地方编写 JSX.tsx
文件只要我们导入我们的jsxFactory
:
import jsx from './jsxFactory';
function Ping({ blurt }: { blurt: string }) {
return <div>{blurt}</div>
}
var el = <Ping blurt="ya"></Ping>;
// var div: HTMLElement
var div = <div id="foo">Hello JSX! {el}</div>;
document.body.appendChild(div)
谢谢JSX.Element
,TypeScript 知道 JSX 的结果是HTMLElement
.