api-typings icon indicating copy to clipboard operation
api-typings copied to clipboard

Component中的FullPropertyToData的定义有问题?

Open zoubin opened this issue 3 years ago • 6 comments

lib.wx.component.d.ts 中

    type PropertyToData<T extends AllProperty> = T extends ShortProperty
        ? ValueType<T>
        : FullPropertyToData<Exclude<T, ShortProperty>>
    type FullPropertyToData<T extends AllFullProperty> = ValueType<T['type']>

当 FullProperty 中 type 为 Object 时,ValueType<T['type']> 总是为 IAnyObject 的,并无法得到推断后具体的类型。 考虑一个例子:

Component({
    properties: {
        person: {
            type: Object,
            value: {
                age: 0,
                name: '',
            }
        }
    },
    attached() {
        this.data.person.age = '1' // 这里预期应当是报错的。但由于 person 被识别为 IAnyObject,被判为通过了
    }
})

但是如果修改成如下的定义后,上面的例子就符合预期了

    type FullPropertyToData<T extends AllFullProperty> = unknown extends T['value'] ? ValueType<T['type']> : T['value']
Component({
    properties: {
        person: {
            type: Object,
            value: {
                age: 0,
                name: '',
            }
        }
    },
    attached() {
        this.data.age = '1' // 符合预期。这里会报错,Type 'string' is not assignable to type 'number'.
    }
})

猜想 T['value'] 是推断后的类型,因此能拿到具体的字段类型信息。

这样修改后,应当可以满足 https://github.com/wechat-miniprogram/api-typings/issues/188 的需求

zoubin avatar Jun 15 '21 08:06 zoubin

确实有效,改了之后会把 type: Object 的情况从 Record<string, any> 限制到具体类型,跑了一下有用例会挂,是个 breaking change,得稍微慎重一点

还有个小问题是 bool: { type: Boolean, value: true } 会推导出 this.data.b: true,应该是有些太严格了,不过字面量的几个类型可以通过 T['type'] 来特殊处理掉

SgLy avatar Jul 05 '21 08:07 SgLy

因为最近在做框架,所以自己按照vue的格式实现了一套接口,用自己包装的注册器转换。

而且我之前也有说过想提pr来着。

小程序这里对比vue就是个大坑。

一个是没有required,理论上没有value的都应该推导出undefined,但实际上没有 第二个就是optionalTypes,导致如果做实际的类型推导必须额外加一个泛型,还要取union,导致类型infer很难做 第三个就是自带的observer,因为需要从 types 和 optionalTypes 同时推断,导致类似vue的as PropType没法work,会存在循环引用或者判断的情况

所以我最终也没找到一个很好的写法。。。

Mister-Hope avatar Jul 05 '21 08:07 Mister-Hope

确实有效,改了之后会把 type: Object 的情况从 Record<string, any> 限制到具体类型,跑了一下有用例会挂,是个 breaking change,得稍微慎重一点

还有个小问题是 bool: { type: Boolean, value: true } 会推导出 this.data.b: true,应该是有些太严格了,不过字面量的几个类型可以通过 T['type'] 来特殊处理掉

true 这个问题,是TS专门针对这个类型进行了处理,会将true/false推断成常量类型,而不是boolean,其它情况应该是OK的,所以可以稍作修改来绕过去

    type FullPropertyToData<T extends AllFullProperty> = unknown extends T['value']  ? ValueType<T['type']>
        : T['value'] extends true | false
        ? boolean
        : T['value']

zoubin avatar Jul 13 '21 07:07 zoubin

确实有效,改了之后会把 type: Object 的情况从 Record<string, any> 限制到具体类型,跑了一下有用例会挂,是个 breaking change,得稍微慎重一点

看了一下 breaking changes:

test/component.test.ts:181:6 ✖ 181:6 Parameter type any[] is not identical to argument type number[]. ✖ 221:6 Parameter type any[] is not identical to argument type number[]. ✖ 246:6 Parameter type any[] is not identical to argument type number[].

test/issue.test.ts:407:8 ✖ 407:8 Parameter type Record<string, any> is declared too wide for argument type { skuNum: number; }.

component.test.ts 中的 3 个应该是正常的,测试用例需要做相应的修改。 issue.test.ts 可以再确认一下,我判断也是需要修改测试用例。

这些用例都是在假定拿到的是 any 来判断的,与添加这个功能后的结果实际不相符

zoubin avatar Jul 13 '21 08:07 zoubin

那改还是不改。 反正怎么改,如果properties值为Object,我定义了接口,类型都推断不出来

hopkinson avatar Nov 25 '21 02:11 hopkinson

因为最近在做框架,所以自己按照vue的格式实现了一套接口,用自己包装的注册器转换。

而且我之前也有说过想提pr来着。

小程序这里对比vue就是个大坑。

一个是没有required,理论上没有value的都应该推导出undefined,但实际上没有 第二个就是optionalTypes,导致如果做实际的类型推导必须额外加一个泛型,还要取union,导致类型infer很难做 第三个就是自带的observer,因为需要从 types 和 optionalTypes 同时推断,导致类似vue的as PropType没法work,会存在循环引用或者判断的情况

所以我最终也没找到一个很好的写法。。。

这个 observer 感觉有点坑,没办法让泛型作用在我们输入的 options 上

07akioni avatar Dec 07 '21 15:12 07akioni