首页 文章

固定长度数组,带有Typescript接口中的可选项

提问于
浏览
2

Angular使用FormBuilder类引入了模型驱动的表单,其主要方法 group 具有如下签名:

group(controlsConfig: {
        [key: string]: any;
    }): FormGroup;

any 实际上是一个格式为的数组:

[
    initial value of model's property, 
    sync validator(s), 
    async validator(s)
]

只需要第一个元素的地方 .

我认为我想要一些比这更强类型的东西,特别是在与强类型模型相关的任何东西上,所以我用T来重新定义函数:

declare interface FormBuilder2 extends FormBuilder {
    group<T>(controlsConfig: {
        [K in keyof T]?: [T[K], ValidatorFn | ValidatorFn[] | null, ValidatorFn | ValidatorFn[] | null];
    }): FormGroup;
}

这也意味着HTML中的所有formControlNames(当然还有group()调用中的所有)必须与我喜欢的模型属性相匹配 .

它似乎工作,但一个snafu:

this.optionsForm = this.formBuilder2.group<CustomerModel>({
        status:    [this.model.status, [Validators.required], null],
        lastOrder: [this.model.lastOrder, null, null],
        comments:  [this.model.comments, null, null],
    });

我必须在未使用的阵列插槽上提供 null .

有没有办法让Typescript省略对无关的 null 的需要?

1 回答

  • 2

    由于元组可以接受额外元素的方式,因此使用元组类型没有真正类型安全的方法 . 也就是说,例如,元组类型 [A, B, C] 实际上将接受 A | B | Csee docs)类型的其他元素 .

    但是,有一个解决方案! (见下面的尝试3)

    (顺便说一句,你忽略了Angular对异步验证器的界面不同: AsyncValidatorFn . )

    Attempt 1:

    [K in keyof T]?: [T[K] | ValidatorFn | ValidatorFn[] | null];
    

    几乎没有 any 打字(可能更糟,因为它看起来有误导性意义) .

    Attempt 2:

    [K in keyof T]?:
      [T[K]] |
      [T[K], ValidatorFn | ValidatorFn[]] |
      [T[K], ValidatorFn | ValidatorFn[] | null, AsyncValidatorFn | AsyncValidatorFn[]];
    

    乍一看似乎更好 . 但问题是Typescript编译器只会抛出错误作为最后的手段 . 所以它会接受这个:

    someStringField: ['hi', 'hello']
    

    因为这符合 [T[K]] (因为Typescript中的元组允许有额外的元素) .

    Attempt 3:

    有一个更好的解决方案,令我惊讶 . 我在撰写这个答案的过程中发现了这一点,同时在Typescript GitHub repo上阅读this issue .

    [K in keyof T]?: {
      0: T[K];
      1?: ValidatorFn | ValidatorFn[];
      2?: AsyncValidatorFn | AsyncValidatorFn[];
    };
    

    这是对先前尝试的改进,因为前三个元素总是被正确地进行类型检查 . ['hi', 'hello'] 正确地给出了编译错误 . 允许其他元素,可以是任何东西,按照通常的结构类型,但没关系 .

    希望这能解决你的问题 .

相关问题