TypeScript中如何为不同类型对象复用同一处理函数?
如何用TypeScript实现通用GraphQL输入字段清理函数?
问题描述
我有多个GraphQL解析器,对应的输入类型分别是doSomethingInput和doSomethingElseInput,这两个输入对象都包含string类型字段。我想用validator.js的escape方法统一清理这些输入字段,防止XSS风险。
在编写通用sanitize函数时,遇到了两类TypeScript类型错误:
- 初始写法报错:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}' - 添加类型断言后报错:
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 会被转义为 "<script>alert("xss")</script>" 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
相关产品推荐
相关产品推荐

