简体   繁体   English

typeScript init 动态类按名称调用 (2345)

[英]typeScript init dynamic class call by name (2345)

How can I call a class without resorting to conditional statements?如何在不诉诸条件语句的情况下调用类?

problem: (parameter) item: inputs Argument of type 'inputs' is not assignable to parameter of type 'ISelect & IText'.问题:(参数)项目:输入“输入”类型的参数不能分配给“ISelect & IText”类型的参数。 Type 'ISelect' is not assignable to type 'ISelect & IText'. “ISelect”类型不能分配给“ISelect & IText”类型。 Property 'placeholder' is missing in type 'ISelect' but required in type 'IText'.(2345) input.ts(12, 5): 'placeholder' is declared here.属性“占位符”在“ISelect”类型中缺失,但在“IText”类型中是必需的。(2345) input.ts(12, 5): 此处声明了“占位符”。

interface IInput {
    id: number
    title: string
}
interface ISelect extends IInput { 
    type: "inputSelect",
    value: string
    selects: string[]
}
interface IText extends IInput{
    type: "inputText",
    placeholder: string
    value: string
}
type inputs = ISelect | IText

class InputSelect implements ISelect {
    public id: number
    public title: string
    public value: string
    public selects: string[]
    public type: ISelect['type'] = "inputSelect"

    constructor(
        inputs: ISelect
    ) { 
        this.id = inputs.id
        this.title = inputs.title
        this.value = inputs.value
        this.selects = inputs.selects
    }

    setValue(value: string) { 
        this.value = value
    }
}

class InputText implements IText {
    public id: number
    public title: string
    public value: string
    public placeholder: string
    public type: IText['type'] = "inputText"

    constructor(
        inputs: IText
    ) { 
        this.id = inputs.id
        this.title = inputs.title
        this.value = inputs.value
        this.placeholder = inputs.placeholder
    }

    setValue(value: string) { 
        this.value = value
    }
}
let b: inputs[] = [
    {
        id: 1,
        title: "some select",
        value: "",
        selects: ["Moskow", "Bejing"],
        type: "inputSelect"
    },
    {
        id: 2,
        title: "some text input",
        value: "",
        placeholder: "yourName",
        type: "inputText"
    }
]
const classes = {
    inputText: InputText,
    inputSelect: InputSelect
}

let a = b.map(item => new classes[item.type](item)) \\here error
console.log(a)

full code typeScript playground link完整代码 typeScript 游乐场链接

because the b is a union of inputs you need to narrow it again in the map function, unfortunately it's a limitation of typescript.因为b是输入的联合,您需要在map函数中再次缩小它的范围,不幸的是,这是 typescript 的限制。

let a = b.map(item =>
    item.type === 'inputSelect' ? new classes[item.type](item) : 
    item.type === 'inputText' ? new classes[item.type](item) : 
    undefined
);

or you can do a dynamic type check, then you need only 1 condition on any amount of interfaces in the inputs union.或者您可以进行动态类型检查,那么您只需要在inputs联合中的任意数量的接口上满足 1 个条件。

const checker = <T extends inputs>(item: T, cl: unknown): cl is ({new (a: T): InstanceType<(typeof classes)[T['type']]>}) => { 
    return classes[item.type] === cl;
};

let a = b.map(item => {
    const cl = classes[item.type];
    return checker(item, cl) ? new cl(item) : undefined;
}).filter((v): v is NonNullable<typeof v> => !!v);

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

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