了解如何在 Expo Router 中使用静态类型的链接和路由。
在你的项目中使用 TypeScript 时可用。Expo Router 开箱即用地支持标准 TypeScript。有关如何设置的更多信息,请参阅 TypeScript 指南。
¥Available when using TypeScript in your project. Expo Router supports standard TypeScript out of the box. See the TypeScript guide for more information on how to set it up.
Expo Router 支持使用 Expo CLI 自动生成 TypeScript 类型。这使得 <Link>
和 钩子 API 能够静态类型化。此功能目前处于测试阶段,默认情况下不启用。
¥Expo Router supports generating TypeScript types automatically with Expo CLI. This enables <Link>
, and the hooks API to be statically typed. This feature is currently in beta and is not enabled by default.
¥Get started
¥Quick start
如果你使用 Expo 路由快速入门指南 创建项目,那么你的项目已配置为使用类型化路由。Expo CLI 将在你第一次运行 npx expo start
时生成所需的类型文件。然后,每当你在 .tsx 文件中使用 Expo Router <Link>
组件时,你都可以对 href
属性使用自动补齐功能。
¥If you created your project using the Expo Router quick start guide then your project is already configured to use typed routes. The Expo CLI will generate the required type file the first time you run npx expo start
. Then, you can use autocomplete for href
props whenever you use an Expo Router <Link>
component in a .tsx file.
¥Manual configuration
虽然该功能处于测试阶段,但你可以通过在 app.json 中将 experiments.typedRoutes
设置为 true
来启用它:
¥While the feature is in beta, you can enable it by setting experiments.typedRoutes
to true
in your app.json:
{
"expo": {
"experiments": {
"typedRoutes": true
}
}
}
运行 npx expo customize tsconfig.json
以配置 tsconfig.json 以添加所需的 includes
字段。
¥Run npx expo customize tsconfig.json
to configure your tsconfig.json to add the required includes
fields.
然后,通过运行 npx expo start
启动开发服务器。你现在可以在 Expo Router <Link>
组件的 href
属性中使用自动补齐功能。
¥Then, start the development server by running npx expo start
. You can now use autocomplete in the Expo Router <Link>
component's href
prop.
¥Type generation
Expo Router 中的类型化路由会在开发服务器启动时自动生成。默认情况下,这些生成的类型配置为不被 Git 跟踪,并将添加到本地 .gitignore 文件中。这可以确保自动生成的文件不会扰乱你的版本控制系统。
¥Typed routes in Expo Router are automatically generated when the development server starts. By default, these generated types are configured to be untracked by Git and will be added to the local .gitignore file. This ensures that autogenerated files do not clutter your version control system.
如果你发现自己需要在不启动开发服务器的情况下生成这些类型,例如在持续集成 (CI) 服务器上进行类型检查期间。为此,请在 CI 上运行命令 npx expo customize tsconfig.json
。
¥If you find yourself in a situation where you need to generate these types without initiating the development server, such as during type checking on a Continuous Integration (CI) server. To do this, run the command npx expo customize tsconfig.json
on the CI.
¥Statically typed routes
使用 Href<T>
的组件和函数现在将是静态类型的,并且具有更严格的定义。例如:
¥Components and functions that use Href<T>
will now be statically typed and have a much stricter definition. For example:
✅ <Link href="/about" />
✅ <Link href="/user/1" />
✅ <Link href={`/user/${id}`} />
✅ <Link href={("/user" + id) as Href} />
// TypeScript errors if href is not a valid route
❌ <Link href="/usser/1" />
对于动态路由,Href 需要是对象,并且它们的参数类型严格:
¥For dynamic routes, Href's need to be objects and their parameters are strictly typed:
✅ <Link href={{ pathname: "/user/[id]", params: { id: 1 }}} />
// TypeScript errors as href is valid, but it should be a HrefObject with params
❌ <Link href="/user/[id]" />
// TypeScript errors as params contain invalid keys
❌ <Link href={{ pathname: "/user/[id]", params: { _id: 1 }}} />
// TypeScript errors as params contain unknown keys
❌ <Link href={{ pathname: "/user/[id]", params: { id: 1, id2: 2 }}} />
¥Relative paths
静态类型的路由不支持相对路径。你需要对所有路由使用绝对路径:
¥Statically typed routes do not support relative paths. You'll need to use absolute paths for all routes:
✅ <Link href="/about" />
// Relative paths are not supported
❌ <Link href="./about" />
你可以利用 expo-router
中的 useSegments()
钩子来创建复杂的相对路径。考虑以下结构:
¥You can leverage the useSegments()
hooks from expo-router
to create complex relative paths. Consider the following structure:
app
(feed)
_layout.tsx
feed.tsx
search.tsx
profile.tsx
(search)
profile.tsx
components
button.tsx
你可以使用 useSegments()
钩子来确保推送到同一选项卡以获取当前路由的第一段。
¥You can ensure that you push to the same tab by using the useSegments()
hook to get the first segment of the current route.
import { Link, useSegments } from 'expo-router';
export function Button() {
const [
// This will be either `(feed)` or `(search)` depending on the current tab.
first,
] = useSegments();
return <Link href={`/${first}/profile`}>Push profile</Link>;
}
现在,你可以利用 app/(feed)/feed.tsx 和 app/(search)/search.tsx 中的 <Button />
来推送 ./profile
,同时保留当前选项卡。
¥Now, you can leverage <Button />
from both app/(feed)/feed.tsx and app/(search)/search.tsx to push ./profile
while preserving the current tab.
¥Imperative navigation
你可以使用键入的 router
对象进行命令式导航:
¥You can use the typed router
object to navigate imperatively:
import { router } from 'expo-router';
router.push('/about');
或者使用键入的 useRouter()
钩子:
¥Or with the typed useRouter()
hook:
import { useRouter } from 'expo-router';
function Page() {
const router = useRouter();
router.push('/about');
// ...
}
¥Query parameters
大多数查询参数不会在文件系统中表示,因此无法自动键入。你可以通过将泛型传递给 useLocalSearchParams
和 useGlobalSearchParams
钩子来手动键入查询参数。例如:
¥Most query parameters will not be represented in the file system and therefore cannot be typed automatically. You can type query parameters manually by passing a generic to the useLocalSearchParams
and useGlobalSearchParams
hooks. For example:
import { Text } from 'react-native';
import { useLocalSearchParams } from 'expo-router';
export default function Page() {
const { query } = useLocalSearchParams<{ query?: string }>();
return <Text>Search: {query ?? 'unset'}</Text>;
}
¥Changes made to the environment
启用类型化路由后,Expo CLI 将在项目的根目录中生成 git 忽略的 expo-env.d.ts 文件,更新 .gitignore 以忽略新的根 expo-env.d.ts 文件,并修改 tsconfig。 json 以包含新的 expo-env.d.ts 文件。
¥When typed routes is enabled, Expo CLI will generate a git ignored expo-env.d.ts file in your project's root directory, update the .gitignore to ignore the new root expo-env.d.ts file, and modify the tsconfig.json to include the new expo-env.d.ts file.
tsconfig.json 中的 includes
字段已更新以包含 expo-env.d.ts 和隐藏的 .expo 目录。这些条目是必需的,不应从文件中删除。
¥The includes
field in your tsconfig.json gets updated to include expo-env.d.ts and a hidden .expo directory. These entries are required and should not be removed from the file.
任何时候都不应删除或更改生成的 expo-env.d.ts。它不应该被提交并且应该被版本控制忽略。
¥The generated expo-env.d.ts should not be removed or changed at any time. It should not be committed and should be ignored by version control.
¥Global types
当启用类型化路由时,Expo CLI 会将以下全局类型添加到你的项目中:
¥Expo CLI will add the following global types to your project when typed routes is enabled:
套 process.env.NODE_ENV = "development" | "production" | "test"
¥Sets process.env.NODE_ENV = "development" | "production" | "test"
允许导入 .[css|sass|scss]
文件
¥Allows the importing of .[css|sass|scss]
files
将 *.module.[css|sass|scss]
的导出设置为 Record<string, string>
¥Sets the exports of *.module.[css|sass|scss]
to be Record<string, string>
添加 Metro 的 require.context
类型。这由 expo/metro-config
启用并用于静态路由生成。
¥Add types for Metro's require.context
. This is enabled by expo/metro-config
and used for static route generation.
启用类型化路由后,Expo CLI 还增强了 react-native
类型以支持 React Native Web。进行了以下更改:
¥With typed routes enabled, Expo CLI also augments the react-native
types to support React Native Web. The following changes are made:
为 ViewStyle
、TextStyle
、ImageStyle
添加其他仅 Web 样式
¥Add additional web-only styles for ViewStyle
, TextStyle
, ImageStyle
将 tabIndex
、aria-level
、lang
添加到 TextProps
¥Add tabIndex
, aria-level
, lang
to TextProps
Pressable 的 children
和 style
状态回调函数中添加 hovered
¥Add hovered
to Pressable's children
and style
state callback function
添加 className
个元素
¥Add className
elements