如何将构造函数接口用作TypeScript泛型类型约束?
解决TypeScript泛型构造函数调用的编译错误
问题根源
TypeScript的泛型仅作用于编译阶段,运行时会被类型擦除。你代码里的T只是类型层面的标记,不是可执行的构造函数对象,所以直接写new T(contents)会触发'T' only refers to a type, but is being used as a value here错误。
修正方案
要复刻Swift中基于协议约束的模式,我们需要让DataStore在运行时能拿到实际的构造函数引用,同时保留类型安全约束:
- 明确
StringDecodable接口的构造函数契约,匹配Swift中可抛出初始化器的语义 - 给
DataStore添加构造参数,传入泛型类型的构造函数实例 - 在
fetchResult中通过传入的构造函数创建实例,并处理可能的错误
完整可运行代码
1. 定义约束接口
// 匹配Swift中StringDecodable协议的语义:接收String参数的可抛出构造函数 interface StringDecodable { new (s: string): this; }
2. 修正DataStore实现
class DataStore<T extends StringDecodable> { constructor( private readonly url: URL, // 新增参数:接收符合约束的构造函数 private readonly decoder: new (s: string) => T ) {} async fetchResult(): Promise<T> { const response = await fetch(this.url); // 先处理HTTP请求错误 if (!response.ok) { throw new Error(`请求失败,状态码: ${response.status}`); } const contents = await response.text(); try { // 通过传入的decoder构造函数创建实例 return new this.decoder(contents); } catch (err) { // 捕获构造函数抛出的解析错误 throw new Error(`解析失败: ${(err as Error).message}`); } } }
3. 实现符合约束的Time类
class Time implements StringDecodable { constructor(s: string) { // 模拟Swift中parseTheTimeString的解析逻辑,解析失败则抛出错误 const timeParts = s.split(':'); if (timeParts.length !== 2) { throw new Error('时间格式错误,需为HH:mm格式'); } const hours = parseInt(timeParts[0], 10); const minutes = parseInt(timeParts[1], 10); if (isNaN(hours) || hours < 0 || hours > 23 || isNaN(minutes) || minutes < 0 || minutes > 59) { throw new Error('时间数值超出有效范围'); } this.hours = hours; this.minutes = minutes; } readonly hours: number; readonly minutes: number; }
4. 使用示例
async function run() { try { const timeUrl = new URL('https://whattimeisit.org/'); // 传入Time构造函数给DataStore const timeStore = new DataStore<Time>(timeUrl, Time); const currentTime = await timeStore.fetchResult(); console.log(`当前时间:${currentTime.hours}:${currentTime.minutes}`); } catch (error) { console.error('处理失败:', (error as Error).message); } } run();
关键说明
- 通过将构造函数
decoder作为参数传入DataStore,解决了TypeScript泛型类型擦除导致的无法调用构造函数问题 - 保留了类型约束,确保只有符合
StringDecodable接口的类型才能被DataStore使用 - 新增了HTTP请求错误和解析错误的处理,贴合Swift中
throws的错误处理语义
内容的提问来源于stack exchange,提问作者goofy4224
相关产品推荐
相关产品推荐

