【问题标题】:Typescript. Typing key value pairs in form structure打字稿。在表单结构中键入键值对
【发布时间】:2017-03-03 11:16:52
【问题描述】:

我正在输入一个运行良好的表单结构。然而,在字段中表单字段的验证部分发生了一些有趣的事情。

我的可视化代码会告诉我phone 常量中的验证“required2”不正确,因为它必须是“必需的”。 但是,当您查看 form 常量的字段集合中的 phonefield 项时,并没有抱怨 required2 是不允许的。 只有当我在界面中设置required时,表单常量才会失效。

我的目标是限制每个表单字段的验证,以便有人无法将键/值添加到未键入的验证字典中。

有趣的是,当我将 phonenumber 更改为 phonenumber2 时,输入将不正确。但是更改所需的密钥并不重要,因为它不是必需的。

我的界面

declare type fields           = IPhoneField | ISelectField ..etc;

export interface IPage {
  title?:               string;
  buttons?:             IButton[];
  fields:               fields[];
  showOn?:              IDictionary <string | number>;
}

export interface IForm {
  modelPreset:          IDictionary <string | number>;
  successPageConfig?:   IDictionary <string | number | boolean>;
  presentation:         pagePresentation;
  pages:                IPage[];
}

interface IField {

  label:                string;
  model:                string;
  placeholder?:         string;
  addon?:               string;
  showOn?:              IDictionary <string | number>;
  maxlength?:           number;

}

export interface IPhoneField extends IField {
  type:                 'phone';
  validation:    {
    required?:          string;
    phonenumber:        string;
  };
}

我的代码

const phone: IPhoneField = {
  "label":"Phone Number",
  "model":"phonenumber",
  "type":"phone",
  "placeholder":"Phone number",
  "validation":{
      "required2":"A phone number is required",
      "phonenumber":"Please enter a valid phone number",

    }
};

const form: IDictionary<IForm> = {
  "form1":{
      "pages":[
        {
            "fields": [
              {
                  "label":"Phone Number",
                  "model":"phonenumber",
                  "type":"phone",
                  "placeholder":"Phone number",
                  "validation":{
                    "required2":"A phone number is required",
                    "phonenumber":"Please enter a valid phone number"
                  }
              }
            ]
        }
      ]
  }
};

有人知道为什么会这样吗?是 Typescript 的 bug 吗?

查看游乐场链接: NEW playground

【问题讨论】:

  • 您能否添加一个playground 链接,其中包含所有定义和有问题的代码?
  • 在我原来的问题中查看游乐场链接
  • 游乐场链接在form结构中也有同样的错误。
  • @NitzanTomer 是的,操场完美。我的 VS Code 或 Gulp 构建不会绊倒 form 常量。我应该在 TS Github 页面上报告这个问题还是应该进一步调查?
  • 如果它在操场上运行良好,那么编译器就没有问题,也没有什么可报告的。您使用的是什么版本的打字稿?直接使用tsc 会有什么反应?

标签: typescript typing


【解决方案1】:

这不是 TypeScript 中的错误。您正在创建类型与其签名不同的对象,因此类型推断不起作用。

首先:phone 中的 required2 不允许在 validation 上使用,因为它是一个无关字段。它与现有的required? 字段没有任何关系。由于您使用的是类型推断,因此添加字段会导致推断的类型不同,即使对象仍然满足接口。

如果你真的想做,你可以把它标记为那个类型。由于您没有接口或类型名称,因此您必须这样做:

const phone: IPhoneField = {
  "label":"Phone Number",
  "model":"phonenumber",
  "type":"phone",
  "placeholder":"Phone number",
  "validation":{
    "required2":"A phone number is required",
    "phonenumber":"Please enter a valid phone number",
  } as { required?: string, phonenumber: string},
};

当然最好是这样:

interface IPhoneValidation {
  required?:          string;
  phonenumber:        string;
}

export interface IPhoneField extends IField {
  type:                 'phone';
  validation:           IPhoneValidation;
}

const phone: IPhoneField = {
  "label":"Phone Number",
  "model":"phonenumber",
  "type":"phone",
  "placeholder":"Phone number",
  "validation":{
    "required2":"A phone number is required",
    "phonenumber":"Please enter a valid phone number",
  } as IPhoneValidation,
}

现在,至于为什么它不抱怨表单中的错误。这是因为您的表单的验证字段根本没有得到类型检查。

由于您还没有发布 IDictionary 实现,因此要找出原因有点猜测。但是使用样板字典实现:

interface IDictionary<T> {
  [K: string]: T;
}

form 声明中出现错误,因此无法分配。重要的是要注意错误不会来自required2,这仅仅是因为您正在组合一组没有类型的深层对象,并且只在最后将它们分配给form,这就是发现无效分配的时候.您可以阅读错误消息并看到它。我明白了:

Type '{ "form1": { "pages": { "fields": { "label": string; "model": string; "type": "phone"; "placehold...' is not assignable to type 'IDictionary<IForm>'.
  Property '"form1"' is incompatible with index signature.
    Type '{ "pages": { "fields": { "label": string; "model": string; "type": "phone"; "placeholder": string...' is not assignable to type 'IForm'.
      Property 'modelPreset' is missing in type '{ "pages": { "fields": { "label": string; "model": string; "type": "phone"; "placeholder": string...'.

这是一个满嘴(并且被钳制)但在某种程度上表明内心深处存在错误。

如果您在赋值期间键入对象,您会更早地收到错误,以便更容易解析,或者如果对象满足接口,则根本不获取它们。例如:

const form: IDictionary<IForm> = {
    "form1": {
        "pages": [
            {
                "fields": [
                    {
                        "label": "Phone Number",
                        "model": "phonenumber",
                        "type": "phone",
                        "placeholder": "Phone number",
                        "validation": {
                            "required2": "A phone number is required",
                            "phonenumber": "Please enter a valid phone number"
                        } as IValidation,
                    } as IField,
                ]
            } as IPage,
        ]
    }
};

在上述情况下,一切都会正常工作,否则当它们存在时您会看到错误。

TypeScript 进行所有这些检查并且不会自动将某些内容作为具有无关字段的接口进行类型转换的原因是为了更严格地避免输入错误。如果它确实允许任何内容,您可以输入 requird 并且永远不会意识到它不是 required,因为它是一个可选字段。换句话说,{required2: ..., phonenumber: ...}允许作为validation 对象,但在没有类型注释的情况下不能自动识别

如果您希望接口自动允许其他属性,您可以这样做:

interface IValidation {
  required?:          string;
  phonenumber:        string;
  [propName:string]:  any;
}

阅读“额外的财产检查”in the interface manual 了解更多信息。

【讨论】:

  • 您好,感谢您的长回答。如果您查看主要故事,我添加了一个游乐场链接。您对字典界面的看法是正确的。奇怪的是,在操场上我确实得到了适当的行为。 Required2 不允许在页面字段内的 phonefield 结构中。我的 Webpack TS-loader 和 TS-lint 以及我的 VS Code 没有抱怨 required2。所以我在那里看到了差异。我的版本是:"ts-loader": "^2.0.0", "tslint": "^4.3.1", "tslint-loader": "^3.3.0", "typescript": "^2.2.1",。也许我应该升级 tslint?
  • TSlint 应该无关紧要。你可能有一个不正确的 TypeScript 版本,虽然 2.2.x 应该没问题。也许确保您的 VSC 的 settings.json 文件设置为 "typescript.tsdk": "node_modules/typescript/lib" 以便它可以使用您的本地项目 TSC,而不是编辑器的。并且您没有全局安装 TypeScript。
  • 嗨,我只是按照你的建议做了:指向 node_ 模块中的本地 TS 版本,它不会改变问题。当验证设置不正确时,form const 仍未标记为有错误。我添加到主要故事中的操场链接的行为与方面相同。我的可视化代码和 gulp 构建过程不是。我应该在 TS Github 页面上报告吗?
  • 查看我在主要故事 cmets 下的评论。 Playground 已更新,我没有包含真正有所作为的字段类型管道:(
  • 啊,我现在明白了。是的,似乎管道是罪魁祸首。 TSC 之前实际上更聪明:即使没有任何类型转换,它也可以告诉你问题出在哪里。但是随着类型的增加,它会丢失。在我看来,它应该知道,因为您的接口可以通过type 识别。但这仍然让人感到困惑。我不会称其为“错误”,但它当然应该能够识别特定错误。 (我的意思是,确实如此,只是不知道在哪里突出显示)。
猜你喜欢
  • 1970-01-01
  • 2021-12-17
  • 2021-03-04
  • 2019-11-28
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 2021-02-02
  • 1970-01-01
相关资源
最近更新 更多