[英]A generic type to describe argument which can be one of few types
This question mainly comes from my previous one on this topic: Declare a custom type for logical argument这个问题主要来自我之前关于这个话题的一个问题: Declare a custom type for logical argument
Here an example:这里有一个例子:
interface ProductType1 {
id: string;
}
interface ProductType2 {
productId: string
}
function getId(product: ???): string {
return product.id || product.productId || string
}
The idea behind this is straight forward: You can pass an object of a type ProductType1
or ProductType2
or a product id itself ( string
)这背后的想法很简单:您可以传递ProductType1
或ProductType2
类型的 object 或产品 ID 本身( string
)
I was trying to do something like:我试图做类似的事情:
type ProductAsArgument = ProductType1 | ProductType2 | string
or或者
interface Product {
id: string;
productId: string;
}
or或者
interface Product {
id?: string;
productId?: string;
}
But as you might guess none of this worked since one of the properties never exist on one of the union types ( ProductType1
, ProductType2
, string
)但正如您可能猜到的那样,这些都不起作用,因为其中一个属性永远不会存在于其中一种联合类型( ProductType1
, ProductType2
, string
)
I believe my go-to option is to create some kind of a smart generic that will inherit a <T>
and will know, that <T>
can be either on of the types I mentioned above.我相信我的首选选项是创建某种智能泛型,它将继承<T>
并且会知道<T>
可以是我上面提到的类型之一。 I might be wrong here but it looks like to me that generic can solve this issue.我在这里可能错了,但在我看来,通用可以解决这个问题。
I found some interesting approaches here How to make one generic type closely dependent on another in TypeScript?我在这里找到了一些有趣的方法如何使 TypeScript 中的一个泛型类型紧密依赖于另一个泛型类型? but still don't understand how to apply it on my case但仍然不明白如何将其应用于我的案例
Can you use classes instead of interfaces?你可以使用类而不是接口吗? In which case you can do something like this, although it would be cleaner to use inheritance for the ProductType classes:在这种情况下,您可以执行以下操作,尽管将 inheritance 用于 ProductType 类会更简洁:
class ProductType1 {
id: string = '1';
}
class ProductType2 {
productId: string = '2';
}
type ProductOrString = ProductType1|ProductType2|string;
function getId(product: ProductOrString): string {
if (product instanceof ProductType1)
return product.id;
else if (product instanceof ProductType2)
return product.productId;
else if (typeof product === 'string')
return product;
else
return 'Error in getId(): Unexpected type';
}
let prod1 = new ProductType1();
let prod2 = new ProductType2();
let prod3 = '3';
console.log(`prod1 ID is ${getId(prod1)}`);
console.log(`prod2 ID is ${getId(prod2)}`);
console.log(`prod3 ID is ${getId(prod3)}`);
TS Playground link TS Playground 链接
Alternatively, using interfaces:或者,使用接口:
interface ProductType1 {
id: string;
}
interface ProductType2 {
productId: string;
}
type ProductOrString = ProductType1|ProductType2|string;
function getId(product: ProductOrString): string {
if (typeof product === 'string')
return product;
else
if ('id' in product)
return product.id;
else if ('productId' in product)
return product.productId;
else
return 'getId(): Unexpected type';
}
let prod1 = { id: '1' };
let prod2 = { productId: '2' };
let prod3 = '3';
console.log(`prod1 ID is ${getId(prod1)}`);
console.log(`prod2 ID is ${getId(prod2)}`);
console.log(`prod3 ID is ${getId(prod3)}`);
Another solution using generics:使用 generics 的另一种解决方案:
type Nullish<T> = T|null|undefined;
type ObjOrStr<T> = T|string;
abstract class BaseProduct
{
id: Nullish<string>;
productId: Nullish<string>;
}
class Product1 extends BaseProduct
{
id: string = 'id1';
}
class Product2 extends BaseProduct
{
productId: string = 'productId2';
}
class SomeClass
{
getProductId<T extends BaseProduct>(product: ObjOrStr<T>)
{
if (typeof product === 'string')
return product;
else
return product.id || product.productId;
}
someMethod<T extends BaseProduct>(product: ObjOrStr<T>)
{
const productName = this.getProductId(product);
return productName;
}
}
let prod1 = new Product1();
let prod2 = new Product2();
let prod3 = 'string3';
let sc = new SomeClass();
console.log(`prod1 id = ${sc.someMethod(prod1)}`);
console.log(`prod2 id = ${sc.someMethod(prod2)}`);
console.log(`prod3 id = ${sc.someMethod(prod3)}`);
I'm not going to directly answer your question.我不会直接回答你的问题。 But for this type of problem但是对于这类问题
You can pass an object of a type ProductType1 or ProductType2 or a product id itself (string).
I will have gone in the direction of functions overriding.我将朝着功能覆盖的方向发展。
function getId(productId: string): string
function getId(product: ProductType1): string
function getId(product: ProductType2): string
function getId(product: string | ProductType1 | ProductType2): string {
if (typeof product === "string")
return product;
else if (product instanceof ProductType1)
...
}
All you need to do is type them您需要做的就是输入它们
interface ProductType1 {
id: string;
}
interface ProductType2 {
productId: string
}
function getId(product: ProductType1 | ProductType2 | string): string {
return (product as ProductType1).id || (product as ProductType2).productId || product as string
}
You can also choose to do typeof product == 'ProductType1'
if statements..你也可以选择做typeof product == 'ProductType1'
if statements..
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.