【问题标题】:fixed-length array with optional items in Typescript interfaceTypescript接口中带有可选项目的固定长度数组
【发布时间】:2017-11-11 16:45:51
【问题描述】:

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 省略对无关 nulls 的需求?

【问题讨论】:

    标签: angular generics typescript interface angular2-formbuilder


    【解决方案1】:

    对于元组类型没有真正类型安全的方法,因为元组可以接受额外的元素。也就是说,例如,元组类型 [A, B, C] 实际上会接受类型为 A | B | C (see 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'] 给出了正确的编译错误。其他元素是允许的,并且可以是任何东西,按照通常的结构类型,但没关系。

    希望这能解决您的问题。

    【讨论】:

    • 聪明!是的,我知道额外的元素是可能的,但这是可以接受的。 (也为我的 AsyncValidatorFn 错过 +1。)
    • 您还可以将初始值指定为具有value 属性和布尔值disabled 属性的对象。要使用尝试 3 覆盖该情况,请将 0: T[K] 更改为 0: T[K]|{ value: T[K]; disabled: boolean }
    • 迟到了,但可以简单地使用type X = [string, string?, number?] 来拥有可选的类型化数组成员
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-08-06
    • 1970-01-01
    • 2017-04-29
    • 1970-01-01
    • 2011-05-30
    • 2011-05-18
    相关资源
    最近更新 更多