You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中如何为不同类型对象复用同一处理函数?

如何用TypeScript实现通用GraphQL输入字段清理函数?

问题描述

我有多个GraphQL解析器,对应的输入类型分别是doSomethingInput和doSomethingElseInput,这两个输入对象都包含string类型字段。我想用validator.js的escape方法统一清理这些输入字段,防止XSS风险。

在编写通用sanitize函数时,遇到了两类TypeScript类型错误:

  1. 初始写法报错:Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'
  2. 添加类型断言后报错:Type 'string' is not assignable to type 'never'

解决方案

要实现通用的输入清理函数,核心是让TypeScript正确识别输入对象的结构,同时确保只处理string类型字段。可以通过泛型约束+类型守卫的组合来解决:

1. 定义基础类型约束

先约束输入对象的结构,确保它是键值对形式,值可以是string或其他类型:

import { escape } from 'validator';

// 约束输入为字符串键的对象,值类型不限
type StringKeyedObject = Record<string, unknown>;

2. 实现带类型安全的通用sanitize函数

通过类型守卫判断字段是否为string,再执行转义,同时用泛型保留原对象的类型信息:

function sanitize<T extends StringKeyedObject>(input: T): T {
  // 复制原对象,避免修改原始数据
  const sanitized = { ...input };

  for (const key in sanitized) {
    if (Object.prototype.hasOwnProperty.call(sanitized, key)) {
      const value = sanitized[key];
      // 类型守卫:仅处理string类型字段
      if (typeof value === 'string') {
        sanitized[key] = escape(value) as T[keyof T];
      }
      // 可选:如果需要处理嵌套对象,可添加递归逻辑
      // if (typeof value === 'object' && value !== null) {
      //   sanitized[key] = sanitize(value as StringKeyedObject) as T[keyof T];
      // }
    }
  }

  return sanitized;
}

3. 针对GraphQL输入类型的使用示例

假设你的GraphQL输入类型定义如下:

type doSomethingInput = {
  username: string;
  age: number; // 非string字段会被自动跳过
};

type doSomethingElseInput = {
  content: string;
  tags: string[]; // 若需处理数组元素,可扩展逻辑遍历数组
};

使用时TypeScript会自动推断返回类型,完全保留原输入的结构:

const input1: doSomethingInput = { username: '<script>alert("xss")</script>', age: 25 };
const sanitizedInput1 = sanitize(input1);
// sanitizedInput1.username 会被转义为 "&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;"

const input2: doSomethingElseInput = { content: '<b>test</b>', tags: ['<tag>'] };
const sanitizedInput2 = sanitize(input2);

错误原因解析

  • 第一个错误:初始写法未给输入对象指定类型约束,TypeScript默认将其视为{},无法用string类型的键索引,因此触发隐式any类型错误。
  • 第二个错误:错误的类型断言导致TypeScript无法推断字段的具体类型,引发类型冲突,最终出现never类型报错。通过泛型约束T extends StringKeyedObject和类型守卫typeof value === 'string',可以让TypeScript正确识别字段类型,规避这类问题。

内容的提问来源于stack exchange,提问作者mrodo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 15:00:04