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

时间:2017-06-09 15:31:06

标签: angular generics typescript interface angular2-formbuilder

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()调用中的所有)必须与模型的属性匹配,我更喜欢这些属性。

这似乎有效,但对于一个人来说:

    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 个答案:

答案 0 :(得分:2)

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

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

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

尝试1:

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

any打字要好得多(可能更糟糕,因为它看起来有误导性)。

尝试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中的元组允许有额外的元素)。

尝试3:

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

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

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

希望这能解决你的问题。

相关问题