如何使用TypeScript编译器API检查类型是否继承另一种类型
问题:TypeScript类型字面量的继承检查失败
我正在开发一款工具,用于将TypeScript定义转换为干净的d.ts文件(而非保留用于调整各类结构的辅助类型)。暂不考虑递归的情况下,工具运行效果良好,但存在一个棘手的限制:我无法检查一种类型字面量是否继承另一种类型,我本以为这是件简单的事。
我尝试了以下代码及多种变体(包括省略getTypeAtLocation):
import ts from 'typescript'; const program = ts.createProgram([], {}) const checker = program.getTypeChecker(); // { result: any } const node1 = ts.factory.createTypeLiteralNode([ ts.factory.createPropertySignature([], "result", undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)) ]); // { something: any } const node2 = ts.factory.createTypeLiteralNode([ ts.factory.createPropertySignature([], "something", undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)) ]); checker.isTypeAssignableTo( checker.getTypeAtLocation(node1), checker.getTypeAtLocation(node2) )
isTypeAssignableTo在检查false/true或string/number这类基础类型时有效,但对类型字面量无效。我可能犯了某个低级错误,要么是解决方案显而易见,要么是这件事本身难度极高不应尝试。
解决方案
问题核心在于直接创建的类型字面量节点没有经过TypeScript的类型绑定阶段,getTypeAtLocation无法正确解析出完整的类型信息。TypeScript的类型检查器需要在有上下文的环境中工作,孤立的AST节点不会被完全处理。
解决步骤
- 创建包含类型字面量的完整源文件:
把类型字面量包装在一个完整的TypeScript源文件中,让程序能正确解析和绑定这些类型。 - 通过符号获取合法类型对象:
从源文件中提取类型的符号,再通过检查器获取对应的类型对象,这样isTypeAssignableTo才能正常工作。
修改后的代码示例
import ts from 'typescript'; // 创建临时源文件,包含两个类型别名 const sourceCode = ` type Type1 = { result: any }; type Type2 = { something: any }; `; // 创建包含该源文件的程序 const program = ts.createProgram( ['temp.ts'], {}, { getSourceFile(fileName, languageVersion) { if (fileName === 'temp.ts') { return ts.createSourceFile( fileName, sourceCode, ts.ScriptTarget.Latest, true ); } return undefined; } } ); const checker = program.getTypeChecker(); const sourceFile = program.getSourceFile('temp.ts')!; // 找到两个类型别名节点 const typeAliases = sourceFile.statements.filter( ts.isTypeAliasDeclaration ) as ts.TypeAliasDeclaration[]; const type1 = checker.getTypeFromTypeNode(typeAliases[0].type); const type2 = checker.getTypeFromTypeNode(typeAliases[1].type); // 现在可正确检查可赋值性(此处返回false,因两个类型结构不匹配) console.log(checker.isTypeAssignableTo(type1, type2)); // false // 测试继承场景:Type3 扩展 Type1 const sourceCodeWithExtends = ` type Type1 = { result: any }; type Type3 = Type1 & { extra: string }; `; // 重复上述步骤获取Type1和Type3的类型后 // checker.isTypeAssignableTo(type3, type1) 会返回true
额外说明
- TypeScript中“类型字面量继承”本质是结构类型的可赋值性,若要检查A是否是B的子类型(即A可赋值给B),
isTypeAssignableTo是正确API,但必须确保类型对象经过完整绑定。 - 若要检查显式继承关系(比如通过
extends关键字),则需遍历AST节点,检查类型字面量的heritageClauses属性,而非依赖类型检查器的可赋值性方法。
内容的提问来源于stack exchange,提问作者Zack Newsham
相关产品推荐
相关产品推荐

