代码之家  ›  专栏  ›  技术社区  ›  Takeshi Tokugawa YD

为什么TypeScript允许枚举具有相同的值?

  •  0
  • Takeshi Tokugawa YD  · 技术社区  · 5 年前

    对于TypeScript 3.9.2,以下代码无效:

    const ResponseDataSpecification = {
        propertiesNames: {
            ID: {
                nameInAPI: "id"
            },
            lettering: {
                nameInAPI: "title"
            }
        }
    }
    
    // I want `nameInAPI`s be in "ResponseDataSpecification"!
    type RequestVariables = {
      [ResponseDataSpecification.propertiesNames.ID.nameInAPI]?: string;
      [ResponseDataSpecification.propertiesNames.lettering.nameInAPI]?: string;
    };
    // A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.(1170)
    

    我想这是故意阻止同名密钥的。

    enum RequestVariablesNames {
      ID = "id",
      lettering = "id" // Mistake simulation
    }
    
    // No errors!!!
    const requestVariables: {
        [RequestVariablesNames.ID ]: string;
        [RequestVariablesNames.lettering ]: string;
    } = {
        [RequestVariablesNames.ID ]: "1",
        [RequestVariablesNames.lettering ]: "test",
    }
    
    console.log(requestVariables); // { "id": "test" } 
    

    结果无效,TypeScript没有阻止它。

    0 回复  |  直到 5 年前
        1
  •  2
  •   Aluan Haddad Vikrant Kashyap    5 年前

    事实上 具有同一密钥的多个属性无效。ECMAScript规范允许使用该代码,要求任何密钥的最新声明获胜。因此 {id: "test"} 在你的例子中。

    From MDN :

    重复的属性名称

    当您的属性使用相同的名称时,第二个属性将覆盖第一个属性。

    let a = {x: 1, x: 2}
    console.log(a) // {x: 2}
    

    在ECMAScript 5的严格模式代码中,重复的属性名被认为是SyntaxError。随着计算属性名称的引入,使得在运行时重复成为可能,ECMAScript 2015消除了这一限制。

    TypeScript以非常高的精度静态建模ECMAScript的语义,并知道结果类型将只有一个属性,要求该属性的所有声明都具有相同的类型:

    enum RequestVariablesNames {
      ID = "id",
      lettering = "id"
    }
    type RequestVariables = {
      [RequestVariablesNames.ID]: number;
      [RequestVariablesNames.lettering]: string; // Error
    };
    

    此外,它知道以下表达式只有一个属性,其类型为 string :

    const requestVariables = {
      [RequestVariablesNames.ID]: 0,
      [RequestVariablesNames.lettering]: "test"
    }
    

    第一个例子不起作用的原因是,类型声明无法知道值是什么,因此也不知道结果类型中属性的键是什么。

    const ResponseDataSpecification = {
      propertiesNames: {
        ID: {
          nameInAPI: "id" // type is string
        },
        lettering: {
          nameInAPI: "title" // type is string
        }
      }
    }
    

    以下方法之所以有效,是因为用于计算键的值在编译时是已知的

    const ResponseDataSpecification = {
      propertiesNames: {
        ID: {
          nameInAPI: "id" as "id" // type is "id"
        },
        lettering: {
          nameInAPI: "title" as "title" // type is "title"
        }
      }
    }
    
    // I want `nameInAPI`s be in "ResponseDataSpecification"!
    type RequestVariables = {
      [ResponseDataSpecification.propertiesNames.ID.nameInAPI]?: string;
      [ResponseDataSpecification.propertiesNames.lettering.nameInAPI]?: string;
    };
    

    价值观 enum 成员在编译时是固有已知的,因此第二个例子,

    enum RequestVariablesNames {
      ID = "id",
      lettering = "id" // Mistake simulation
    }
    

    作品。

    推荐文章