能否在TypeScript接口中排除指定类型,实现符合自定义toString要求的Stringable约束?
类型层面实现自定义Stringable校验的方案
完全可以在TypeScript类型系统中实现你要求的校验逻辑,实现思路和代码如下:
核心实现代码
首先定义黑名单类型、合法toString判断的条件类型,最终组合出你需要的Stringable类型:
// 第一步:定义需要排除的黑名单类型 type BlacklistedTypes = | null | undefined | symbol | Object | Array<any> | Map<any, any> | Promise<any> | Set<any> // 第二步:判断类型是否符合toString要求 type HasValidToString<T> = T extends BlacklistedTypes ? false // 排除toString为Object原型方法的类型 : T['toString'] extends typeof Object.prototype.toString ? false // 排除toString为Array原型方法的类型 : T['toString'] extends typeof Array.prototype.toString ? false // 校验toString方法返回值为string : T extends { toString: () => string } ? true : false // 最终导出的Stringable类型 type Stringable<T = unknown> = T extends unknown ? (HasValidToString<T> extends true ? T : never) : never
效果验证
// 合法通过的类型 const str: Stringable = 'text' // 字符串原始类型 const num: Stringable = 123 // 数字原始类型 const bool: Stringable = false // 布尔原始类型 const bigint: Stringable = 100n // bigint原始类型 const customObj: Stringable = { toString: () => 'custom string' } // 自定义toString的对象 // 会报错的非法类型 const sym: Stringable = Symbol('s') // symbol被排除 const nullVal: Stringable = null // null被排除 const arr: Stringable = [1,2] // 数组被排除 const map: Stringable = new Map() // Map被排除 const plainObj: Stringable = {} // 普通对象被排除 const promise: Stringable = Promise.resolve(1) // Promise被排除
注意事项
TypeScript的类型系统是结构化类型系统,无法完全模拟运行时的原型链动态判断,但上述实现已经可以覆盖你提出的所有过滤要求。如果后续需要新增排除类型,直接往BlacklistedTypes联合类型中添加即可。
内容的提问来源于stack exchange,提问作者user6275749
相关产品推荐
相关产品推荐

