Typescript 如何指定依赖于构造函数参数的类型变量

Typescript 如何指定依赖于构造函数参数的类型变量,typescript,Typescript,像这样的班级: class Extractor<T, K extends keyof T> { constructor(private item: T, private key: K) { } extract(): T[K] { return this.item[this.key]; } } 类提取器{ 构造函数(私有项:T,私有密钥:K){} 提取():T[K]{ 返回此.item[此.key]; } } 使用/扩展不自然,因为类型参数

像这样的班级:

class Extractor<T, K extends keyof T> {
    constructor(private item: T, private key: K) { }

    extract(): T[K] {
        return this.item[this.key];
    }
}
类提取器{
构造函数(私有项:T,私有密钥:K){}
提取():T[K]{
返回此.item[此.key];
}
}
使用/扩展不自然,因为类型参数K采用字符串文字类型

我希望类型参数是
,其中
R
实际上是先前计算的
T[K]
。但是,TypeScript不允许
R
引用构造函数参数,并且
key
参数的类型表达式不允许引用参数本身。此外,构造函数不能具有泛型类型参数


那么,我在哪里可以指定约束条件,即
R=T[typeof key]

我不确定您想要实现什么,所以我不知道哪种解决方案最适合您:


可以使用从类型
T
和所需的
R
计算
K
,但这可能会带来比解决问题更多的麻烦:

type ValueOf<T> = T[keyof T];
type KeyofMatching<T, R extends ValueOf<T>> = 
  ValueOf<{ [K in keyof T]: T[K] extends R ? K : never }>;
现在您可以定义您的类:

class Extractor<T, R extends T[keyof T]> {
  constructor(private item: T, private key: KeyofMatching<T, R>) { }
  extract(): R {
    return asR(this.item[this.key]); // note the asR()
  }
}
如果您想要尽可能窄的
R
,则必须明确指定:

const e = new Extractor<{a: string, b: boolean}, boolean>({a: "you", b: true}, "b");
如果你使用
make
而不是构造函数,你会得到你想要的行为和推论,我认为:

const e = Extractor.make({ a: "you", b: true }, "b");
// e is an Extractor<{a: string, b: boolean}, boolean>
const e=Extractor.make({a:“你”,b:true},“b”);
//e是一个提取器

因此,这是可行的,避免了早期方法的问题,但可能会增加一些自身的问题。感谢您对各种可能性的全面总结。我有一种感觉,我想要的不是真正实用的。我之所以希望将类型
R
作为类型参数,而不是
K
,是因为实际的
提取器
是一个抽象基类,有许多引用
R
的方法和许多需要重新声明这些类型参数的子类型。对于我的团队(有着丰富的Java背景)来说,处理引用类而不是字符串文本的类型变量是非常自然的。
const e = new Extractor<{a: string, b: boolean}, boolean>({a: "you", b: true}, "b");
class Extractor<T, R extends T[keyof T]> {
  constructor(private item: T, private extractorFunction: (x: T) => R) { }
  extract(): R {
    return this.extractorFunction(this.item);
  }
  static make<T, K extends keyof T>(item: T, key: K): Extractor<T, T[K]> {
    return new Extractor(item, i => i[key]);
  }
}
const e = Extractor.make({ a: "you", b: true }, "b");
// e is an Extractor<{a: string, b: boolean}, boolean>