---
title: '类型覆盖'
description: 覆盖参数和返回值的 TypeScript 类型。
---

# 类型覆盖

在大多数情况下，**NAPI-RS** 会根据 Rust 签名生成正确的 TypeScript 类型。只有当公开的 TypeScript 契约有意不同于运行时转换类型时才应覆盖，并在测试中保持两种行为一致。

[ThreadsafeFunction](./threadsafe-function) 就是一个例子：`build_callback` 闭包可以把拥有所有权的 Rust 数据转换为另一组 JavaScript 回调参数，因此类型推断不一定能描述最终的回调签名。

## `ts_args_type`

替换导出函数完整的、逗号分隔的参数列表。这只会改变生成的声明，不会改变运行时转换。

**lib.rs**

```rust {10}
use std::sync::Arc;
use std::thread;

use napi::{
  bindgen_prelude::*,
  threadsafe_function::{ThreadsafeCallContext, ThreadsafeFunctionCallMode},
};
use napi_derive::napi;

#[napi(ts_args_type = "callback: (err: null | Error, result: string) => void")]
pub fn call_threadsafe_function(callback: Function<u32, ()>) -> Result<()> {
  let tsfn_builder = callback.build_threadsafe_function();
  let tsfn = Arc::new(
    tsfn_builder
      .callee_handled::<true>()
      .build_callback(
        move |ctx: ThreadsafeCallContext<u32>| Ok(format!("n: {}", ctx.value)),
      )?,
  );
  for n in 0..100 {
    let tsfn = tsfn.clone();
    thread::spawn(move || {
      tsfn.call(Ok(n), ThreadsafeFunctionCallMode::Blocking);
    });
  }
  Ok(())
}
```

⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️

**index.d.ts**

```ts
export function callThreadsafeFunction(
  callback: (err: null | Error, result: string) => void,
): void
```

## `ts_arg_type`

*单独*替换一个或多个参数类型。NAPI-RS 会继续推断其他参数。

**lib.rs**

```rust {1}
#[napi]
fn override_individual_arg_on_function(
  not_overridden: String,
  #[napi(ts_arg_type = "() => string")] f: Function<(), String>,
  not_overridden2: u32,
) -> Result<String> {
  let value = f.call(())?;
  Ok(format!("{not_overridden}-{value}-{not_overridden2}"))
}
```

**index.d.ts**

```ts
export function overrideIndividualArgOnFunction(
  notOverridden: string,
  f: () => string,
  notOverridden2: number,
): string
```

## `ts_return_type`

替换生成的返回类型。对于异步导出，请提供完整的公开类型，通常为 `Promise<T>`。

**lib.rs**

```rust {1}
#[napi(ts_return_type="number")]
fn return_something_unknown<'env>(env: &'env Env) -> Result<Unknown<'env>> {
  env.create_uint32(42).map(|v| v.to_unknown())
}
```

**index.d.ts**

```ts
export function returnSomethingUnknown(): number
```

## `ts_type`

覆盖结构体字段所生成的 TypeScript 类型。

**lib.rs**

```rust {1}
#[napi(object)]
pub struct TsTypeChanged {
  #[napi(ts_type = "MySpecialString")]
  pub type_override: String,

  #[napi(ts_type = "object")]
  pub type_override_optional: Option<String>,
}
```

**index.d.ts**

```ts
export interface TsTypeChanged {
  typeOverride: MySpecialString
  typeOverrideOptional?: object
}
```

## 在文件头中添加自定义类型定义

NAPI-RS 生成 `index.d.ts` 时会包含默认文件头。你可以自定义该文件头，添加原生模块所需的 TypeScript 类型、import 或注释。

### 使用场景

- **自定义类型别名**：定义 API 使用的 `MaybePromise<T>` 等类型
- **导入外部类型**：导入 `ReadableStream`、`Buffer` 或其他 Node.js 类型
- **ESLint/TypeScript 指令**：添加 `// @ts-nocheck` 或自定义规则
- **文档**：版权声明、版本信息或弃用警告
- **声明 symbol**：导出绑定使用的常量或 symbol

### 配置选项

| 方法              | 位置      | 最适合                   |
| ----------------- | --------- | ------------------------ |
| `dtsHeaderFile`   | napi 配置 | 包含 import 的复杂文件头 |
| `dtsHeader`       | napi 配置 | 简单的单行补充内容       |
| `--dts-header`    | CLI 标志  | CI/CD 覆盖               |
| `--no-dts-header` | CLI 标志  | 完全禁用文件头           |

### 优先级解析

同时设置多个选项时，NAPI-RS 按以下顺序解析：

| 优先级 | 来源                    | 说明                                            |
| :----: | ----------------------- | ----------------------------------------------- |
|   1    | `dtsHeaderFile`（配置） | `napi` 配置中的文件路径——**只要设置就始终优先** |
|   2    | `--dts-header`（CLI）   | CLI 标志会覆盖内联配置                          |
|   3    | `dtsHeader`（配置）     | `napi` 配置中的内联字符串                       |
|   4    | 默认文件头              | 未指定其他选项时使用                            |

> **要点**：配置中的 `dtsHeaderFile` 优先于所有其他选项，包括 `--dts-header` CLI 标志。如果需要通过 CLI 覆盖，请使用 `dtsHeader`，而不是 `dtsHeaderFile`。

### 示例场景

| 配置 `dtsHeaderFile` | 配置 `dtsHeader` | CLI `--dts-header` | 结果                 |
| :------------------: | :--------------: | :----------------: | -------------------- |
|   `./header.d.ts`    |  `"type X = Y"`  |  `"// override"`   | 使用 `./header.d.ts` |
|          -           |  `"type X = Y"`  |  `"// override"`   | 使用 `"// override"` |
|          -           |  `"type X = Y"`  |         -          | 使用 `"type X = Y"`  |
|          -           |        -         |         -          | 使用默认文件头       |

### 使用 `dtsHeaderFile`（推荐）

对于复杂的文件头，请创建单独的 `.d.ts` 文件：

**第 1 步：创建文件头文件**

**dts-header.d.ts**

```typescript
/* auto-generated by NAPI-RS */
/* eslint-disable */

import type { ReadableStream } from 'node:stream/web'

type MaybePromise<T> = T | Promise<T>

export declare const MY_SYMBOL: symbol
```

**第 2 步：在 package.json 中引用它**

**package.json**

```json
{
  "napi": {
    "dtsHeaderFile": "./dts-header.d.ts"
  }
}
```

> ⚠️ 该文件的内容会**完全替换**默认文件头。如果希望保留自动生成的注释和 eslint 指令，请把它们包含在文件中。

### 使用 `dtsHeader`（内联）

对于简单的补充内容，请在配置中使用内联字符串：

**package.json**

```json
{
  "napi": {
    "dtsHeader": "type MaybePromise<T> = T | Promise<T>"
  }
}
```

这会完全替换默认文件头。如果希望保留自动生成的注释和 eslint 指令，请把它们包含在字符串中。

### CLI 选项

**`--dts-header`**：通过 CLI 覆盖文件头（适用于 CI/CD）：

```sh
napi build --dts-header "// Custom header"
```

**`--no-dts-header`**：生成不含任何文件头的 `.d.ts`：

```sh
napi build --no-dts-header
```

### 默认文件头

未自定义时，NAPI-RS 使用：

```typescript
/* auto-generated by NAPI-RS */
/* eslint-disable */
```
