我需要一种通过课堂访问obj的方法. 为此,我想使用泛型类型.

问题是,在类中,我得到了一个错误—它是不可能判断这个. locators是否包含输入字段.

 type '{ form1: { item2: { checkbox: string; input: string; }; }; form2: { item1: { checkbox: string; }; }; }[T][F]' is not assignable to type 'object'.
  Type '{ form1: { item2: { checkbox: string; input: string; }; }; form2: { item1: { checkbox: string; }; }; }[T][keyof { form1: { item2: { checkbox: string; input: string; }; }; form2: { item1: { checkbox: string; }; }; }[T]]' is not assignable to type 'object'.
    Type '{ form1: { item2: { checkbox: string; input: string; }; }; form2: { item1: { checkbox: string; }; }; }[T][string] | { form1: { item2: { checkbox: string; input: string; }; }; form2: { item1: { checkbox: string; }; }; }[T][number] | { ...; }[T][symbol]' is not assignable to type 'object'.
      Type '{ form1: { item2: { checkbox: string; input: string; }; }; form2: { item1: { checkbox: string; }; }; }[T][string]' is not assignable to type 'object'

如何解决?我想提一下,类型必须从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')

推荐答案

这是一个已知的错误或打印脚本的限制,报告为microsoft/TypeScript#21760.当您开始对generics执行乘法indexed accesses时,编译器将倾向于失go 对泛型constraints的跟踪,并最终将它们扩大到导致错误的东西.除非这一问题得到解决(这似乎不太可能,或者至少没有迹象表明它正在被处理),否则您将需要解决它.

一般来说,当你知道类型X可以赋给类型Y,但编译器不知道这一点时,你可以经常使用intersection X & Y来代替X. 如果你对可赋值性的看法是正确的,那么X & Y最终将等同于X(函数类型有一些例外,但在这里并不直接相关).但是编译器将接受X & Y可以通过交集的定义赋给Y.

一种解决办法是将ObjType[PK][FK]object相交,这样打字脚本将允许您使用the in operator:

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]是非空的,所以我在这里使用了non-null assertion operator (!).

或者你可以做更多的运行时判断,让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 link to code

Typescript相关问答推荐

在TypScript手册中可以视为接口类型是什么意思?

如何使用属性作为具有Generics的TypScript类中的类型守护?

typescribe警告,explate—deps,useEffect依赖项列表

接口的额外属性作为同一接口的方法的参数类型'

打印脚本丢失函数的泛型上下文

隐式键入脚本键映射使用

学习Angular :无法读取未定义的属性(正在读取推送)

使用TypeScrip根据(可选)属性推断结果类型

为什么我的一个合成函数不能推断类型?

分解对象时出现打字错误

已解决:如何使用值类型限制泛型键?

使用TypeScrip的类型继承

将对象的属性转换为正确类型和位置的函数参数

如何键入派生类的实例方法,以便它调用另一个实例方法?

我不明白使用打字脚本在模板中展开参考

在REACT查询中获取未定义的isLoading态

基于属性值的条件类型

带有过滤键的 Typescript 映射类型

基于泛型的柯里化函数的条件参数

使用react+ts通过props传递数据