跳至主要内容
版本: v18.0.0

类型发射

作为其正常工作的一部分,Relay 编译器 将为您的选择语言发射类型信息,帮助您编写类型安全的应用程序代码。这些类型包含在 relay-compiler 生成的用于描述您的操作和片段的工件中。

操作变量

用于查询、变异或订阅操作的变量对象的形状。

在这个例子中,发射的类型信息将要求变量对象包含一个 artistID 键,它是一个非空字符串。

/**
* export type ExampleQuery$variables = {
* readonly artistID: string
* }
* export type ExampleQuery$data = {
* readonly artist?: {
* readonly name?: string
* }
* }
* export type ExampleQuery = {
* readonly variables: ExampleQuery$variables
* readonly response: ExampleQuery$data
* }
*/
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
}
}
`,
// variables are expected to be of type ExampleQuery$variables
{artistID: 'banksy'},
);

操作和片段数据

操作或片段中选择的数据形状,遵循数据掩码规则。也就是说,排除片段扩展选择的所有数据。

在这个例子中,发射的类型信息描述了由 useLazyLoadQuery(或 usePreloadedQuery)返回的响应数据。

/**
* export type ExampleQuery$variables = {
* readonly artistID: string
* }
* export type ExampleQuery$data = {
* readonly artist?: {
* readonly name?: string
* }
* }
* export type ExampleQuery = {
* readonly variables: ExampleQuery$variables
* readonly response: ExampleQuery$data
* }
*/

// data is of type ExampleQuery$data
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
}
}
`,
{artistID: 'banksy'},
);

return props.artist && <div>{props.artist.name} is great!</div>

同样,在这个例子中,发射的类型信息描述了道具的类型,以匹配 useFragment 预计接收的片段引用的类型。

/**
* export type ExampleFragmentComponent_artist$data = {
* readonly name: string
* }
*
* export type ExampleFragmentComponent_artist$key = { ... }
*/

import { ExampleFragmentComponent_artist$key } from "__generated__/ExampleFragmentComponent_artist.graphql"

interface Props {
artist: ExampleFragmentComponent_artist$key,
};

export default ExampleFragmentComponent(props: Props) {
// data is of type ExampleFragmentComponent_artist$data
const data = useFragment(
graphql`
fragment ExampleFragmentComponent_artist on Artist {
biography
}
`,
props.artist,
);

return <div>About the artist: {props.artist.biography}</div>;
}

片段引用

数据掩码中描述的不透明标识符,子容器期望从其父级接收,它代表子容器在其父级片段内的片段扩展。

考虑一个组合上面片段组件示例的组件。在这个例子中,子组件发射的类型信息接收一个唯一的非透明标识符类型,称为片段引用,它由父级片段引用在子级片段扩展的位置发射的类型信息引用。因此,确保子级的片段扩展到父级的片段中,并且在运行时将正确的片段引用传递给子组件。

import { ExampleFragmentComponent } from "./ExampleFragmentComponent"

/**
* import { ExampleFragmentComponent_artist$fragmentType } from "ExampleFragmentComponent_artist.graphql";
*
* export type ExampleQuery$data = {
* readonly artist?: {
* readonly name: ?string,
* readonly " $fragmentSpreads": ExampleFragmentComponent_artist$fragmentType
* }
* }
* export type ExampleQuery$variables = {
* readonly artistID: string
* }
* export type ExampleQuery = {
* readonly variables: ExampleQuery$variables
* readonly response: ExampleQuery$data
* }
*/

// data is of type ExampleQuery$data
const data = useLazyLoadQuery(
graphql`
query ExampleQuery($artistID: ID!) {
artist(id: $artistID) {
name
...ExampleFragmentComponent_artist
}
}
`,
{artistID: 'banksy'},
);

// Here only `data.artist.name` is directly visible,
// the marker prop $fragmentSpreads indicates that `data.artist`
// can be used for the component expecting this fragment spread.
return <ExampleFragmentComponent artist={data.artist} />;

单个工件目录

需要注意的重要警告是,默认情况下,严格的片段引用类型信息不会发射,而是它们将被类型化为 any,并允许您向子组件传递任何数据。

要启用此功能,您必须告诉编译器将所有工件存储在一个目录中,方法是在编译器配置中指定 artifactDirectory

{
// package.json
"relay": {
"artifactDirectory": "./src/__generated__",
...
},
...
}

…并在您的 .babelrc 配置中另外通知 babel 插件在何处查找工件

{
"plugins": [
["relay", { "artifactDirectory": "./src/__generated__" }]
]
}

建议在您的模块解析配置中为该目录创建别名,这样您就不需要在源文件中指定相对路径。这也是上面示例中所做的,其中工件是从 __generated__ 别名导入,而不是像 ../../../../__generated__ 这样的相对路径。

背景信息

原因是 relay-compiler 及其工件发射是无状态的。这意味着它不会跟踪原始源文件的 位置,以及编译器之前将随附的工件保存在磁盘上的位置。因此,如果编译器要发射尝试从其他工件导入片段引用类型的工件,编译器将

  • 首先需要知道该其他工件在磁盘上的位置;
  • 以及当该其他工件在磁盘上更改位置时更新导入。

Facebook 使用一个名为Haste的模块系统,其中所有源文件都被视为处于扁平命名空间中。这意味着导入声明不需要指定另一个模块的路径,因此编译器不需要考虑上述问题。即导入只需要指定模块文件名 的基本名称,Haste 在导入时负责实际找到正确的模块。然而,在 Facebook 之外,Haste 模块系统的使用是不存在的,也不鼓励,因此决定不导入片段引用类型,而是将它们类型化为 any

最简单地说,我们可以将 Haste 看作一个包含所有模块文件的单个目录,因此所有模块导入始终可以使用相对同级路径安全地导入。这就是单个工件目录功能所实现的。不是将工件与它们的源文件共置,而是将所有工件存储在一个目录中,允许编译器发射片段引用类型的导入。


此页面是否有用?

通过以下方式帮助我们使网站更完善 回答几个简单的问题.