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

TypeScript泛型类构造器参数类型守卫触发ts(4063)错误求助

Fixing TypeScript Error TS(4063) in Generic Service Class Constructor

Let's break down what's going wrong here and how to fix it.

The Root Cause of the Error

Your constructor parameter type C extends Converters is invalid TypeScript syntax. C extends Converters is a conditional type check, not a valid type annotation for a parameter. TypeScript can't parse this correctly, which leads to the confusing "private name" error (it's a compiler misinterpretation of the invalid syntax, not an issue with unexported types).

Your goal is clear:

  1. Allow the constructor to optionally accept a Converters instance
  2. Have the generic type C reflect whether a converter was provided (to drive the Names and Value types)

The Correct Approach

We need to adjust the generic constraint and constructor parameter type to properly link the input to the generic type. Here's the fixed implementation:

import { Converter } from "./characteristic";
export { Converter } from "./characteristic";

export type Converters = Record<string, Converter<any>>;
export type Names<C> = C extends Converters ? keyof C : string | number;
export type Value<C, N extends Names<C>> = C extends Converters ? ConvertersValue<C, N> : Buffer;
export type ConvertersValue<
  C extends Converters,
  N extends Names<C>
> = C[N] extends Converter<infer V> ? V : never;

export default class Service<C extends Converters | undefined = undefined> {
  private converters?: Converters;

  // Constructor now accepts a parameter of type C (either Converters or undefined)
  constructor(converters?: C) {
    this.converters = converters;
  }

  public async read<N extends Names<C>>(name: N): Promise<Value<C, N>> {
    throw new Error("Not implemented yet");
  }
}

Key Changes Explained

  1. Generic Constraint & Default Value:
    We set C extends Converters | undefined = undefined to:

    • Restrict C to either a Converters object or undefined
    • Provide undefined as the default type when no converter is passed, which triggers your fallback typings for Names and Value
  2. Constructor Parameter Type:
    Using converters?: C directly links the input parameter to the generic type. TypeScript will automatically infer C as Converters when you pass a converter object, or use the default undefined when you don't.

How This Works in Practice

  • No converter provided:

    const service = new Service();
    const result = await service.read("any-key"); // result is Buffer
    

    Here, C defaults to undefined, so Names<C> becomes string | number and Value<C, N> becomes Buffer.

  • Converter provided:

    const tempConverter = { convert: (buf: Buffer) => buf.readUInt16LE(0) } as Converter<number>;
    const service = new Service({ temp: tempConverter });
    const temp = await service.read("temp"); // temp is number
    

    TypeScript infers C as the type of your converter object, so Names<C> is keyof C (in this case "temp") and Value<C, N> is the inferred type from the converter (number).

Why Your Original Syntax Failed

Writing converters?: C extends Converters tries to use a conditional check as a type, which isn't allowed. Parameters need explicit, concrete types (or types derived from generics with valid constraints). The compiler misinterpreted this invalid syntax as a reference to an unexported private type, hence the TS(4063) error.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 07:45:48