Typescript 我是否可以使用类型作为值(或从构造函数参数正确推断泛型类类型)?

Typescript 我是否可以使用类型作为值(或从构造函数参数正确推断泛型类类型)?,typescript,typescript-generics,Typescript,Typescript Generics,我有一个泛型类,它接受另一个类型和这个类型的键名。我还想用这个密钥名初始化属性。我已经在TS中定义了它,但我必须显式地将键的名称作为泛型参数传递给构造函数,并将相同的值传递给构造函数。看起来有点不必要-这些值总是相同的类型和值 是否可以从泛型类的构造函数参数推断其类型?或者使用泛型类型作为值,可能不是-我有一个错误:“ValueKey”只引用一个类型,但在这里被用作值。ts2693 带定义的代码: interface InterfaceWithProperties { stringPro

我有一个泛型类,它接受另一个类型和这个类型的键名。我还想用这个密钥名初始化属性。我已经在TS中定义了它,但我必须显式地将键的名称作为泛型参数传递给构造函数,并将相同的值传递给构造函数。看起来有点不必要-这些值总是相同的类型和值

是否可以从泛型类的构造函数参数推断其类型?或者使用泛型类型作为值,可能不是-我有一个错误:“ValueKey”只引用一个类型,但在这里被用作值。ts2693

带定义的代码:

interface InterfaceWithProperties {
    stringProperty: string;
    numberProperty: number;
}

class GenericCLass<TypeWithKeys, ExactKey extends keyof TypeWithKeys> {
    keyNameFromAnotherType: ExactKey; // this property should have value equal to key from another type;

    // is it a way to remove this parameter? it's exactly duplicated with ExactKey
    // or to detect correctly ExactKey type based on `property` value
    constructor(keyNameFromAnotherType: ExactKey) {
        // this.property = ExactKey; // ofc: not working code
        this.keyNameFromAnotherType = keyNameFromAnotherType;
    }
}
当前使用情况:

const test1 = new GenericCLass<InterfaceWithProperties, 'stringProperty'>('stringProperty');
我想要相同的结果,但没有这个额外的参数。大概是这样的:

const test2 = new GenericCLass<InterfaceWithProperties, 'stringProperty'>();
const test3 = new GenericCLass<InterfaceWithProperties>('stringProperty');
或者像这样的smth:

const test2 = new GenericCLass<InterfaceWithProperties, 'stringProperty'>();
const test3 = new GenericCLass<InterfaceWithProperties>('stringProperty');

使用以下代码执行操作:

问题是您希望手动指定一个类型参数,并让编译器推断另一个类型参数。这被调用,TypeScript在TS3.4中没有。您可以手动指定所有不希望执行的类型参数,也可以让编译器推断所有类型参数,但您无法执行这些操作,因为您无法从中推断指定的类型

对于这种情况,有两种主要的解决方法:

第一种方法是完全依赖类型推断,并使用伪参数推断通常指定的类型。例如:

class GenericCLass<T, K extends keyof T> {
    keyNameFromAnotherType: K; 

    // add dummy parameter
    constructor(dummy: T, keyNameFromAnotherType: K) {
        this.keyNameFromAnotherType = keyNameFromAnotherType;
    }
}

const test = new GenericCLass(null! as InterfaceWithProperties, 'stringProperty');
// inferred as GenericCLass<InterfaceWithProperties, "stringProperty">
这样就只剩下类定义了,但创建了一个新的helper函数,该函数返回部分指定版本的GenericClass构造函数供您使用。你可以一次完成,但很难看:

const test = new (genericClassMaker<InterfaceWithProperties>())('stringProperty');
// inferred as GenericCLass<InterfaceWithProperties, "stringProperty">

不管怎样,希望其中一个对你有用。祝你好运

问题是您想要手动指定一个类型参数,并让编译器推断另一个类型参数。这被调用,TypeScript在TS3.4中没有。您可以手动指定所有不希望执行的类型参数,也可以让编译器推断所有类型参数,但您无法执行这些操作,因为您无法从中推断指定的类型

对于这种情况,有两种主要的解决方法:

第一种方法是完全依赖类型推断,并使用伪参数推断通常指定的类型。例如:

class GenericCLass<T, K extends keyof T> {
    keyNameFromAnotherType: K; 

    // add dummy parameter
    constructor(dummy: T, keyNameFromAnotherType: K) {
        this.keyNameFromAnotherType = keyNameFromAnotherType;
    }
}

const test = new GenericCLass(null! as InterfaceWithProperties, 'stringProperty');
// inferred as GenericCLass<InterfaceWithProperties, "stringProperty">
这样就只剩下类定义了,但创建了一个新的helper函数,该函数返回部分指定版本的GenericClass构造函数供您使用。你可以一次完成,但很难看:

const test = new (genericClassMaker<InterfaceWithProperties>())('stringProperty');
// inferred as GenericCLass<InterfaceWithProperties, "stringProperty">

不管怎样,希望其中一个对你有用。祝你好运

坏消息是你不能轻易做到这一点。最好的方法是让编译器根据构造函数参数推断ExactKey。只有让typescript推断出所有类型参数,才能做到这一点。但是您需要指定一个类型参数并推断另一个,这是不可能的,因为至少在3.5中不支持部分推断,有计划添加它,但它被推回,然后从路线图中删除

一种选择是将函数curry与静态函数而不是构造函数一起使用:

interface InterfaceWithProperties {
    stringProperty: string;
    numberProperty: number;
}

class GenericCLass<TypeWithKeys, ExactKey extends keyof TypeWithKeys> {
    keyNameFromAnotherType: ExactKey; 
    private constructor(keyNameFromAnotherType: ExactKey) {
        this.keyNameFromAnotherType = keyNameFromAnotherType;
    }
    static new<T>(){
        return function <ExactKey extends keyof T>(keyNameFromAnotherType: ExactKey) {
            return new GenericCLass<T, ExactKey>(keyNameFromAnotherType);
        }         
    } 
}


const test1 = GenericCLass.new<InterfaceWithProperties>()('stringProperty')
或者,如果您害怕使用null作为InterfaceWithProperties,则可以使用类型类:


这两种解决方案都不是很好,也不是特别直观,都不是最好的解决方案。

最糟糕的新情况是,你不能轻易做到这一点。最好的方法是让编译器根据构造函数参数推断ExactKey。只有让typescript推断出所有类型参数,才能做到这一点。但是您需要指定一个类型参数并推断另一个,这是不可能的,因为至少在3.5中不支持部分推断,有计划添加它,但它被推回,然后从路线图中删除

一种选择是将函数curry与静态函数而不是构造函数一起使用:

interface InterfaceWithProperties {
    stringProperty: string;
    numberProperty: number;
}

class GenericCLass<TypeWithKeys, ExactKey extends keyof TypeWithKeys> {
    keyNameFromAnotherType: ExactKey; 
    private constructor(keyNameFromAnotherType: ExactKey) {
        this.keyNameFromAnotherType = keyNameFromAnotherType;
    }
    static new<T>(){
        return function <ExactKey extends keyof T>(keyNameFromAnotherType: ExactKey) {
            return new GenericCLass<T, ExactKey>(keyNameFromAnotherType);
        }         
    } 
}


const test1 = GenericCLass.new<InterfaceWithProperties>()('stringProperty')
或者,如果您害怕使用null作为InterfaceWithProperties,则可以使用类型类:


这两种解决方案都不是好的,也不是特别直观的,都是最好的解决方案。

伟人的想法是一样的:我留下我的答案,因为我认为类型版本可能有一些用途,您的函数返回构造函数方法也很好,这两个答案都很好,并且建议使用类型来删除null强制转换!我使用@jcalz中的curry helper函数,因为我需要的是构造函数本身,而不是实例。非常感谢-每件事都很有魅力:伟大的思想都是一样的:我将留下我的答案,因为我认为类型版本可能有一些用途,而你的有函数返回构造函数的方法,这也很好。两个答案都很好,并且建议使用类型来删除null强制转换!我使用@jcalz中的curry helper函数,因为我需要的是构造函数本身,而不是实例。非常感谢-一切都很有魅力: