Javascript TypeScript中的嵌套结构中是否可能有一个可变类型参数?

Javascript TypeScript中的嵌套结构中是否可能有一个可变类型参数?,javascript,typescript,Javascript,Typescript,与这个问题相对应的一个简单示例是“一个简单的通用类型和类型安全的类似LinkedList的数据结构”,其中每个下一个节点可以是不同的类型。例如,目的是实现这一点: interface LinkedNode<T1> { value: T1; next: LinkedNode<T2> | null; // Typescript gives error for T2 here. } Use case: inte

与这个问题相对应的一个简单示例是“一个简单的通用类型和类型安全的类似LinkedList的数据结构”,其中每个下一个节点可以是不同的类型。例如,目的是实现这一点:

     interface LinkedNode<T1> {
        value: T1;
        next: LinkedNode<T2> | null; // Typescript gives error for T2 here.
      }

Use case:
      interface IPair{
        a:boolean;
        b: number;
      }
      let LinkedNode1: LinkedNode<string> = {value: "string1", next: null};
      let LinkedNode2: LinkedNode<number> = {value: 10, next: LinkedNode1};
      let LinkedNode3: LinkedNode<IPair> = {value: {a:true, b: 2}, next: LinkedNode2};
      let root: LinkedNode<boolean> = {value: true, next: LinkedNode3};

      let x = root.next.value.a; // ultimately this is the desired effect: to be able to get access to other linked node's member variables without having to manually typecast.
接口链接节点{
值:T1;
next:LinkedNode | null;//Typescript在这里给出了T2的错误。
}
用例:
接口IPair{
a:布尔型;
b:数字;
}
让LinkedNode1:LinkedNode={value:“string1”,next:null};
让LinkedNode2:LinkedNode={value:10,next:LinkedNode1};
让LinkedNode3:LinkedNode={value:{a:true,b:2},next:LinkedNode2};
让root:LinkedNode={value:true,next:LinkedNode3};
设x=root.next.value.a;//最终,这就是所期望的效果:能够访问其他链接节点的成员变量,而无需手动类型转换。

因此,问题是:“对于上面的
LinkedNode
接口,用
替换
会编译,但会丢失类型信息。不使用
代替
,是否可以达到上述预期效果?如果不是,还有什么替代方法?”

如果我理解正确,您真的需要一种类型,其中元组中的每个元素向下一级进入树中。或者至少这是唯一对我有意义的事情,因为您必须根据所有子体的类型定义根节点的类型

如果有一些,您可以执行以下操作:

// get the first element of a tuple; Head<[1,2,3]> is 1
type Head<L extends any[]> = 
  ((...l: L) => void) extends ((h: infer H, ...t: infer T) => void) ? H : never;

// get the tuple with the first element removed; Tail<[1,2,3]> is [2,3]
type Tail<L extends any[]> = 
  ((...l: L) => void) extends ((h: infer H, ...t: infer T) => void) ? T : never;

// represent LinkedNode in the following nested way
interface LinkedNode<T extends any[]> {
  value: Head<T>;
  next: LinkedNode<Tail<T>> | null; 
}
我觉得不错


在TS3.0之前,您可以通过嵌套泛型获得一些东西,这可能更简单:

interface LinkedNode<T, N extends null | LinkedNode<any, any>=null> {
  value: T;
  next: N;
}

const node: LinkedNode<string, LinkedNode<number, LinkedNode<boolean>>> = {
  value: "a",
    next: {
    value: 1,
      next: {
      value: true,
        next: null
    }
  }
};

let LinkedNode1: LinkedNode<string> = {value: "string1", next: null};
let LinkedNode2: LinkedNode<number, typeof LinkedNode1> = {value: 10, next: LinkedNode1};
let LinkedNode3: LinkedNode<IPair, typeof LinkedNode2> = {value: {a:true, b: 2}, next: LinkedNode2};
let root: LinkedNode<boolean, typeof LinkedNode3> = {value: true, next: LinkedNode3};
接口链接节点{
值:T;
下一步:N;
}
常量节点:LinkedNode={
价值:“a”,
下一步:{
价值:1,
下一步:{
价值观:正确,
下一个:空
}
}
};
让LinkedNode1:LinkedNode={value:“string1”,next:null};
让LinkedNode2:LinkedNode={value:10,next:LinkedNode1};
让LinkedNode3:LinkedNode={value:{a:true,b:2},next:LinkedNode2};
让root:LinkedNode={value:true,next:LinkedNode3};

看起来也不错。其中一个有帮助吗?

考虑到第一个节点是数字,下一个是字符串,下一个是日期,第一个项目节点是数字,下一个是字符串,当您执行下一个操作时,下一个是字符串,下一个是日期,那么,所有的泛型类型使用较少,但是在您的情况下,您需要定义
LinedNode
来解决typescript错误它肯定会为备选方案列表添加另一个透视图,但我遇到的问题是,一旦这种类型的结构被传递给由工厂函数动态创建和销毁的方法/函数,就有必要使用越来越高级别的类型抽象,例如使用继承。那么,是否可以将“next”成员本身的“Type”存储在另一个成员变量中,如:interface INode{value:T,nextNodeType:Type of T2,next:INode}?但是,我相信这可能是不可能的,因为这可能需要类型反射。我不确定我是否理解。。。如果你有一个具体的用例和一个附带的,也许有人能够回答。好吧,我可以用纯Javascript做我想做的事情,或者用Typescript中的
any
替换相应的类型。我尝试了使用rest参数和spread运算符的可变泛型类型,这种类型独立工作。然而,将这些作为参数传递给更高级别的工厂函数会使代码变得复杂,并且在某些地方需要再次手动转换。我放弃了我原来的结构/实现,因为我想要实现的似乎不可能以简洁的方式实现。举个简单的例子,我们可以在
类中为
方法
引入一个新的类型参数
。但是,对于类的
数据成员
,我们不能这样做。我知道这听起来很奇怪(甚至可能会破坏打字的目的),但直到我遇到一个
class A{f1(p:T1){return p;}/*数据成员d1是复杂数据类型的某种类型*/d1:T2;/*这是不可能的*/}
无论如何,我相信上面的回答确实在某种程度上用当前的语言特性回答了这个问题,因此,我将其标记为答案。
interface LinkedNode<T, N extends null | LinkedNode<any, any>=null> {
  value: T;
  next: N;
}

const node: LinkedNode<string, LinkedNode<number, LinkedNode<boolean>>> = {
  value: "a",
    next: {
    value: 1,
      next: {
      value: true,
        next: null
    }
  }
};

let LinkedNode1: LinkedNode<string> = {value: "string1", next: null};
let LinkedNode2: LinkedNode<number, typeof LinkedNode1> = {value: 10, next: LinkedNode1};
let LinkedNode3: LinkedNode<IPair, typeof LinkedNode2> = {value: {a:true, b: 2}, next: LinkedNode2};
let root: LinkedNode<boolean, typeof LinkedNode3> = {value: true, next: LinkedNode3};