TypeScript中如何为构造函数类型指定类型参数并标注派生类实例
动态派生泛型类的TypeScript类型标注问题
我创建了一个基类并编写了泛型工厂函数,用于在运行时动态派生子类,但在标注派生类实例的类型时遇到了困难——部分类型参数信息丢失了。想确认TypeScript是否能准确标注这类派生对象的类型。
泛型二叉树基类
/** @template T, U, V */ class BinaryTree { /** @type {T} */ tag /** * @param {U} left * @param {V} right */ constructor(left, right) { this.left = left this.right = right } }
叶子节点派生类
/** * @template T * @extends BinaryTree<T, null, null> */ class Leaf extends BinaryTree { tag = 'leaf' constructor() { super(null, null) } }
泛型工厂函数
/** * @template {string} T * @template {BinaryTree<string, any, any>} U * @template {BinaryTree<string, any, any>} V * @param {T} tag * @returns {new <U, V>(l:U, r:V) => BinaryTree<tag,U,V>} */ function makeBinaryTreeClass(tag) { return { [tag]: /** * @template U, V * @extends BinaryTree<tag, U, V> */ class extends BinaryTree { tag = tag } }[tag] }
使用示例与问题
现在可以通过工厂函数创建带特定标签的树节点类:
const TaggedTreeNode = makeBinaryTreeClass('tag') const node1 = new TaggedTreeNode(new Leaf(), new Leaf())
目前node1的类型被正确推断为BinaryTree<'tag', Leaf<any>, Leaf<any>>,但当我尝试用InstanceType<...>获取构造函数的返回类型来标注数组时,子节点的类型被细化成了unknown:
/** @type {Array<InstanceType<TaggedTreeNode>>} */ const arrayOfTaggedTreeNodes = [node1] // 实际类型:`BinaryTree<"tag", unknown, unknown>[]` // 期望类型:`BinaryTree<"tag", BinaryTree<string, any, any>, BinaryTree<string, any, any>>[]` arrayOfTaggedTreeNodes[0].left // 类型是unknown!
由于标签需要在运行时传入,我不想硬编码类型为BinaryTree<"tag", ...>。
补充说明
因为要求派生类的名称必须动态设置,所以不得不使用{[tag]: class {...}}[tag]这个技巧。如果移除工厂函数的@returns标注,TypeScript会把返回类型推断为typeof [tag],这更不符合预期:
/** * @template {string} T * @param {T} tag */ function makeBinaryTreeClass(tag) { return { [tag]: /** * @template U, V * @extends BinaryTree<tag, U, V> */ class extends BinaryTree { tag = tag } }[tag] } const TaggedTreeNode = makeBinaryTreeClass('tag') // 推断类型:`typeof [tag]`
内容的提问来源于stack exchange,提问作者Andy Pan
相关产品推荐
相关产品推荐

