如何使用通用类型来访问对象

问题描述 投票:0回答:1

我需要一种通过类访问 obj 的方法。 我想为此使用通用类型。

问题是在类中我收到错误 - 无法检查 this.locators 是否包含输入字段。

如何解决?我想提一下,类型必须从

const obj
推断出来,我不想定义任何接口/类型。

const obj = {
    form1: {
        item2: {
            checkbox: 'checkbox',
            input: 'input',
        }
    },
    form2: {
        item1: {
            checkbox: 'busin'
        }
    }
};

type ObjType = typeof obj;
type ProgramKeys = keyof ObjType;
type FormKeys<T extends ProgramKeys> = keyof ObjType[T];



class CheckboxFormOne<T extends ProgramKeys, F extends FormKeys<T>> {
    locators:  ObjType[T][F];

    constructor(public program: T, public form: F) {
        this.locators = obj[program][form];
    }


    fillInput(input: keyof typeof obj[T][F]) {  
        if ('input' in this.locators && typeof this.locators[input] === 'string') {
            this.locators.input
        }
    }
}
new CheckboxFormOne('form1', 'item2').fillInput('input')
typescript oop
1个回答
0
投票

这是 TypeScript 的一个已知错误或限制,报告于 microsoft/TypeScript#21760。当您开始使用泛型进行多个索引访问时,编译器往往会失去对泛型约束的跟踪,并最终将它们扩大到导致错误的东西。除非这个问题得到解决(这似乎不太可能,或者至少没有迹象表明它正在解决),否则您将需要解决它。

通常,当您知道类型

X
可以分配给类型
Y
但编译器不知道这一点时,您通常可以使用 交集
X & Y
代替
X
。如果您对可分配性的看法是正确的,那么
X & Y
最终将等同于
X
(函数类型有一些例外,但这与这里不直接相关)。但编译器会接受
X & Y
可以通过交集的定义分配给
Y

一种解决方法是将

ObjType[PK][FK]
object
相交,以便 TypeScript 允许您使用
in
运算符
:

class CheckboxFormOne<PK extends ProgramKeys, FK extends FormKeys<PK>> {
    locators: object & ObjType[PK][FK]; // constrain to object

    constructor(public program: PK, public form: FK) {
        this.locators = obj[program][form]! // assert non-nullish
    }

    fillInput(input: keyof typeof obj[PK][FK]) {
        if ('input' in this.locators && typeof this.locators[input] === 'string') {
            this.locators.input
        }
    }
}

请注意,编译器仍然无法确定

obj[program][form]
是非空的,因此我在那里使用 非空断言运算符 (
!
)

或者你可以做更多的运行时检查来说服 TS

this.locations
是一个对象:

class CheckboxFormOne<PK extends ProgramKeys, FK extends FormKeys<PK>> {
    locators: ObjType[PK][FK];

    constructor(public program: PK, public form: FK) {
        this.locators = obj[program][form];
    }

    fillInput(input: keyof typeof obj[PK][FK]) {
        // do extra runtime tests
        if (this.locators && typeof this.locators === "object" &&
            'input' in this.locators && typeof this.locators[input] === 'string') {
            this.locators.input
        }
    }
}

其中任何一个都不是特别好,还有其他也不是很好的方法,但重点是你需要以某种方式解决它。

Playground 代码链接

© www.soinside.com 2019 - 2024. All rights reserved.