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

如何使用TypeScript AST解析泛型条件类型以获取变量真实类型?

Solution: Resolve Type Aliases Recursively for Conditional Type Checks

When dealing with conditional types that reference type aliases (like BarTypeParent in your example), the key is to recursively resolve those aliases down to their underlying base types before evaluating the extends condition. Here's how to implement this with ts-morph:

Step 1: Build a Recursive Type Resolver

First, create a function that takes a TypeScript type and resolves all nested type aliases until it reaches a non-alias base type (like string, number, a class type, etc.).

import { Type, SyntaxKind, TypeAliasDeclaration } from "ts-morph";

/**
 * Recursively resolves a type alias to its underlying base type
 */
function resolveToBaseType(type: Type): Type {
  // Get the symbol associated with the type, if it exists
  const typeSymbol = type.getSymbol();
  if (!typeSymbol) return type;

  // Find the first type alias declaration for this symbol
  const typeAliasDecl = typeSymbol.getDeclarations().find(
    dec => dec.isKind(SyntaxKind.TypeAliasDeclaration)
  ) as TypeAliasDeclaration | undefined;

  // If we found an alias, recursively resolve its target type
  if (typeAliasDecl) {
    return resolveToBaseType(typeAliasDecl.getType());
  }

  // No alias found—return the original type
  return type;
}

Step 2: Update Your Conditional Type Evaluation Logic

Modify your existing code to use this resolver when checking the extends clause in conditional types. Remember that in TypeScript's conditional types, T extends U checks assignability, not strict inheritance—so we'll use ts-morph's isAssignableTo method after resolving both types.

Here's how to integrate this with your existing flow:

// Assume you've already retrieved the variable's type (e.g., BarType<string> for barVar)
const variableType = project.getSourceFile("your-file.ts")?.getVariableDeclaration("barVar")?.getType();
const genericType = variableType?.getAliasTypeArguments()[0].getType();
const conditionalType = genericType?.getConditionalType();

if (conditionalType) {
  const extendsClause = conditionalType.getExtendsClause();
  
  // Resolve both sides of the extends clause to their base types
  const resolvedLeft = resolveToBaseType(extendsClause.getLeft().getType());
  const resolvedRight = resolveToBaseType(extendsClause.getRight().getType());

  // Check if the left type is assignable to the right (matches T extends U logic)
  const satisfiesExtends = resolvedLeft.isAssignableTo(resolvedRight);

  if (satisfiesExtends) {
    // Get the "true" branch type (e.g., string in BarType)
    const realType = conditionalType.getTrueType();
    console.log(`Real type of barVar: ${realType.getText()}`);
  } else {
    // Get the "false" branch type (e.g., number in BarType)
    const realType = conditionalType.getFalseType();
    console.log(`Real type of barVar: ${realType.getText()}`);
  }
}

Step 3: Handle Edge Cases

This approach works for most common scenarios, but you may want to extend it for edge cases like:

  • Nested type aliases: type A = B; type B = string; will resolve correctly to string
  • Generic type aliases: type Wrapper<T> = T; type MyString = Wrapper<string>; will resolve to string
  • Union/intersection types: If your alias points to a union (e.g., type MyUnion = string | number), resolveToBaseType will return the union directly, and isAssignableTo will handle it as expected

Explanation for Your Specific Example

For your BarType code:

type BarTypeParent = string;
type BarType<T> = T extends BarTypeParent ? string : number;
let barVar: BarType<string>;
  1. We resolve BarTypeParent to its base type string
  2. We resolve the substituted T (which is string) to itself
  3. Check if string is assignable to string → true
  4. Return the true branch type string, which is the real type of barVar

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 09:44:07