TypeScript 泛型 - 有条件地设置泛型接口类型的参数,并将实现类对象作为值


interface myGenericInterface<T> {
propX : T;
}
class implementationA implements myGenericInterface<string> {
propX : string;
}
class implementationB implements myGenericInterface<number> {
propX : number;
}
class sample<T> {
prop : myGenericInterface<T>;
constructor( x : any) {
if(typeof x === "string"){
prop = new implementationA(); // Error reported here. how do I achieve this? 
}
}
}

线路错误 -prop = new implementationA()媒体资源"内容"的类型不兼容。 类型"字符串"不可分配给类型"T"。 "T"可以用与"字符串"无关的任意类型实例化

在这种情况下使用泛型的正确方法是什么?如何有条件地设置具有myGenericInterface类型的类属性。

问题

class sample<T>是一个泛型类,其中this.prop的类型取决于该实例的泛型类型参数T的类型。

通常,设置泛型类,以便从传递给构造函数的参数推断实例的T类型。 您的构造函数只有(x : any),因此T的类型将始终unknown,除非您通过调用new sample<string>("")来显式设置它。

参数xany,所以可以调用new sample<number>("")。 在这种情况下,Tnumber. 但是typeof x === "string"true所以您将设置this.prop,必须myGenericInterface<number>implementationA哪个是myGenericInterface<string>。 所以希望你能明白为什么Typescript在这一行给你一个错误。

<小时 />

平庸的解决方案

我认为你想做的是x属于T型,并约束T使其只能stringnumber

你可以这样做,但它不是100%的类型安全的,因为它要求我们做出一个可能是正确的断言,但我们不能保证。 当我们检查typeof x === "string"时,会将x类型细化为仅string,但它不会细化T的类型,因为从技术上讲,T可能是联合string | numberTstring的子集。 所以我们必须使用as来抑制打字稿错误。

class sample<T extends string | number> {
prop: myGenericInterface<T>;
constructor(x: T) {
if (typeof x === "string") {
// x is known to be string, but we don't know that T is string
this.prop = new implementationA() as myGenericInterface<T>
} else {
this.prop = new implementationB() as myGenericInterface<T>
}
}
}
<小时 />

良好的解决方案

我们可以保证任何类型(不仅仅是string | number)的类型安全,如果我们只是创建实现myGenericInterface<T>的对象。 如果我们将propX设置为x,那么我们不需要知道或关心T的实际类型是什么,因为我们知道x可以分配给T所以{propX: x}可以分配给myGenericInterface<T>

class sample<T> {
prop: myGenericInterface<T>;
constructor(x: T) {
this.prop = {
propX: x,
}
}
}

您可以使用此方法与额外的步骤一起使用,方法是使用泛型类来实现myGenericInterface<T>

class GenericImplementation<T> implements myGenericInterface<T> {
propX: T;
constructor(value: T) {
this.propX = value;
}
}
class sample<T> {
prop: myGenericInterface<T>;
constructor(x: T) {
this.prop = new GenericImplementation(x);
}
}

打字稿游乐场链接

通过class sample<T> {,您将T绑定到某种可能既不string也不number的未知类型。如果T例如number[](数组),则prop的类型myGenericInterface<number[]>不能分配类型为myGenericInterface<string>的值。

你能做的是改为

class sample {
prop : myGenericInterface<string|number>;
constructor( x : any) {
if(typeof x === "string"){
this.prop = new implementationA();  // Now works
}
}
}

操场

最新更新