简体   繁体   English

任何 class 作为 typescript 中的 function 参数

[英]any class as function argument in typescript

Suggestion needed: As a newbie, I have class like below in typescript :需要的建议:作为一个新手,我在 typescript 中有如下class

export declare class SampleOne extends Setting {
    getValue(): Promise<boolean>;
    setValue(value: boolean): Promise<void>;
}

And

export declare class SampleTwo extends Setting {
    getValue(): Promise<boolean>;
    setValue(value: boolean): Promise<void>;
}

Now i want a helper function where i can pass either SampleOne or SampleTwo like below:现在我想要一个助手 function 我可以通过SampleOneSampleTwo如下所示:

async function getObj(title: string, categories: string, cname: Setting) {

    let obj = await et.findSetting(title,categories) as cname;// i want to pass either **SammpleOne** or **SampleTwo** class.
    return obj;
}

Function call would be like Function 调用就像

getObj(title, categories, SampleOne) getObj(标题,类别,SampleOne)

getObj(title, categories, SampleTwo) getObj(标题,类别,SampleTwo)

I am strangling to created this helper function.How it should be looks like in typescript??我正在扼杀创建这个助手 function。它在 typescript 中应该是什么样子?

Thanks in advance.提前致谢。

You can make getObj generic by the type of Setting and parametrize the last argument as a constructor of T:您可以通过Setting的类型使getObj通用,并将最后一个参数参数化为 T 的构造函数:

type Class<T> = new (...args: any) => T;

async function getObj<T extends Setting>(
    title: string, categories: string, klass: Class<T>): Promise<T> 
{
    return .... as  T
}

I would go with Convenience generic pattern我会使用方便通用模式的 go

async function getObj<T extends Setting>(title: string, categories: string): Promise<T> {
    let obj = await et.findSetting(title,categories) as T;
    return obj;
}

or, dropping the unncecessary async:或者,删除不必要的异步:

function getObj<T extends Setting>(title: string, categories: string): Promise<T> {
    return et.findSetting(title,categories) as Promise<T>;
}

Usage:用法:

const s1 = getObj<SampleOne>('a', 'b');

Pros:优点:

  • can be used if you model Setting as a class如果您将 model 设置为 class 则可以使用
  • can be used if you model Setting as an interface如果你可以使用 model 设置为接口

Cons:缺点:

  • no runtime check (which may or may not be a problem)没有运行时检查(这可能是也可能不是问题)

If you need runtime check and have settings modeled as classes, you can use Type (as coded by Angular folks):如果您需要运行时检查并将设置建模为类,则可以使用Type (由 Angular 人员编码):

interface Type<T> extends Function { new (...args: any[]): T; }

async function getObj<T extends Setting>(
    title: string, categories: string, klass: Type<T>): Promise<T> 
{
   let obj = await et.findSetting(title,categories);
   if (klass.prototype.isPrototypeOf(obj)) {
    return obj as T; 
   } else {
     throw new Error(`Expected ${klass.name} but got ${obj.constructor.name}`)
   }
   
}

const s1 = getObj('a', 'b', SampleOne);
s1.then(x => console.log(x))
  .catch(e => console.log(e));

I believe you can just apply this constraint T extends typeof Setting to generic:我相信你可以只应用这个约束T extends typeof Setting到泛型:

class Setting {
    getValue(): Promise<boolean> { return Promise.resolve(true) };
    setValue(value: boolean): Promise<void> { return Promise.resolve() };
}


class SampleOne extends Setting {
    getValue(): Promise<boolean> { return Promise.resolve(true) };
    setValue(value: boolean): Promise<void> { return Promise.resolve() };
}

class SampleTwo extends Setting {
    getValue(): Promise<boolean> { return Promise.resolve(true) };
    setValue(value: boolean): Promise<void> { return Promise.resolve() };
}

class DontAllowed { }

type AllowedClasses = typeof SampleOne | typeof SampleTwo

class SampleThree { // does not extends Setting
    getValue(): Promise<boolean> { return Promise.resolve(true) };
    setValue(value: boolean): Promise<void> { return Promise.resolve() };
}

function getObj<T extends typeof Setting>(cname: T) {
    return cname
}

const result = getObj(SampleOne) // ok
const result2 = getObj(SampleTwo) // ok
const result3 = getObj(DontAllowed) // expected error

In above example, I assumed that every class which extends Setting is allowed.在上面的例子中,我假设每个扩展设置的 class 都是允许的。 If you want to allow anly two classes, you can do this thing:如果你想只允许两个类,你可以这样做:


type AllowedClasses = typeof SampleOne | typeof SampleTwo

function getObj<T extends AllowedClasses>(cname: T) {
    return cname
}

Playground 操场

I don't think that it is necessary to use type assertion ( as operator) in such cases.我认为在这种情况下没有必要使用类型断言( as运算符)。

Use generics .使用generics

async function getObj<T>(title: string, categories: string) {

    let obj = await et.findSetting(title,categories) as T;
    return obj;
}

Then you can call the function with the desired type:然后您可以使用所需的类型调用 function:

getObj<SampleOne>('foo', 'bar');
getObj<SampleTwo>('foo', 'bar');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM