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

TypeScript约束顺序方法调用:实现同泛型形状组件的类型断言API

问题:创建兼具运行时API与类型断言的接口报错

我想创建一个同时支持运行时API和类型断言的接口,要求传入的两个组件必须基于相同形状的泛型。但代码一直报错,错误信息如下:

Argument of type 'typeof A' is not assignable to parameter of type 'Component<any>'.
  Property '[S]' is missing in type 'typeof A' but required in type 'Component<any>'.

相关代码示例:

import {expectTypeOf} from 'expect-type';

declare const S: unique symbol;

declare class Component<S> {
  declare private [S]: S;
}

type InferSignature<T> = T extends Component<infer Signature> ? Signature : never;

declare class A extends Component<{
  name: string;
  age: number;
}> {};

declare class B extends Component<{
  mismatch: true
}> {}

function fromThis<T extends Component<any>>(ThisComponent: T) {
  return {
    toThat<R extends Component<InferSignature<T>>>(ThatComponent: R) {
      return {
        withRuntimeTest( testName: string) {
          if (window.location.search.includes(testName)) {
            return ThatComponent;
          }

          return ThisComponent;
        }
      }
    }
  }
}

// 类型推断正常
type ASig = InferSignature<A>;
type BSig = InferSignature<B>;

// 这是我期望的断言行为
expectTypeOf<ASig>().toEqualTypeOf(BSig)

// 但这里的类型检查不符合预期
fromThis(A).toThat(B).withRuntimeTest('my-b-test')

问题分析与修复方案

错误原因

报错的核心是:Component类中定义的私有符号属性[S]不会被子类的构造函数类型继承。我们传入的A和B是类本身(构造函数),而非类的实例,但原代码的类型约束T extends Component<any>是针对实例类型的,导致类型不匹配。

修复后的完整代码

import {expectTypeOf} from 'expect-type';

declare const S: unique symbol;

declare class Component<S> {
  declare private [S]: S;
}

// 调整工具类型:从组件构造函数中提取泛型签名
type InferSignature<T> = T extends typeof Component<infer Sig> ? Sig : never;

declare class A extends Component<{
  name: string;
  age: number;
}> {};

declare class B extends Component<{
  mismatch: true
}> {}

// 约束参数为Component的子类构造函数类型
function fromThis<T extends typeof Component<any>>(ThisComponent: T) {
  return {
    // 强制目标组件的泛型签名与源组件完全一致
    toThat<R extends typeof Component<InferSignature<T>>>(ThatComponent: R) {
      return {
        withRuntimeTest(testName: string) {
          if (window.location.search.includes(testName)) {
            return ThatComponent;
          }
          return ThisComponent;
        }
      }
    }
  }
}

// 类型推断正常工作
type ASig = InferSignature<A>;
type BSig = InferSignature<B>;

// 这里会正确触发类型错误,符合预期的断言行为
expectTypeOf<ASig>().toEqualTypeOf(BSig)

// 仅当传入泛型签名匹配的组件时才通过类型检查
// fromThis(A).toThat(A).withRuntimeTest('my-a-test') // 合法
fromThis(A).toThat(B).withRuntimeTest('my-b-test') // 正确报错:类型不匹配

关键修复点

  1. 调整类型约束对象:将fromThis的参数约束从实例类型Component<any>改为构造函数类型typeof Component<any>,匹配我们传入的类本身。
  2. 更新泛型提取逻辑:修改InferSignature工具类型,从构造函数类型中正确提取泛型参数。
  3. 强化类型断言:toThat的约束R extends typeof Component<InferSignature<T>>确保目标组件的泛型签名与源组件完全一致,实现了预期的类型校验,同时保留原有的运行时逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 12:51:56