【问题标题】:What's the difference between TypeScript const assertions and declarations?TypeScript const 断言和声明之间有什么区别?
【发布时间】:2019-08-09 08:52:18
【问题描述】:

我刚刚阅读了 TypeScript 3.4 RC 中新的 const 断言功能,但我没有看到它与使用 const 声明有何不同。

我使用来自announcement page 的示例对此进行了测试,该示例显然演示了使用as constconst 断言)如何防止文字类型被扩大(例如,"circle"string)。

// Example from official announcement
function getShapes() {
  let result = [
    { kind: "circle", radius: 100 },
    { kind: "square", sideLength: 50 },
  ] as const;

  return result;
}

for (const shape of getShapes()) {
  if (shape.kind === "circle") {
    console.log("Circle radius", shape.radius);
  } else {
    console.log("Square side length", shape.sideLength);
  }
}

// Output:
// Circle radius 100
// Square side length 50

但是,当我删除 const 断言并改用 const 声明时,编译器输出控制台输出没有任何变化,也没有引发错误。

// Altered getShapes function
function getShapes() {
  const result = [
    { kind: "circle", radius: 100 },
    { kind: "square", sideLength: 50 },
  ];

  return result;
}

那么有什么区别呢?公告页面列出了使用const断言的三个理由:

&项目符号;不应扩大该表达式中的文字类型(例如,不要从“hello”变为字符串)
&子弹;对象字面量获取只读属性
&子弹;数组字面量变成只读元组

但它没有解释断言和声明有何不同。

【问题讨论】:

  • 您的示例没有像公告示例那样使用Shape 类型。如果您将其包含在自己的示例中,您会看到差异。
  • @Aaron 我不确定你的意思。我更改的示例与最初的示例完全相同,但更改了 const 使用。
  • 将返回类型注释添加到getShapes(),你会看到TS给你的“可怕的错误信息”(公告措辞)没有 const断言。

标签: typescript typescript3.0


【解决方案1】:

const 声明是声明后无法更改的变量声明。这是 Typescript 支持的 Javascript 功能。

const x ={ n: 10} ;
x.n = 11; //ok
x= { n:11}; // error 

const 断言是一种类型断言,它对断言目标具有您所描述的影响。

const x ={ n: 10} as const;
x. n = 11; // error n is readonly 

【讨论】:

  • 有道理。因此,公告中的例子只是一个坏例子。
  • @Adam 您的示例缺少公告示例用来显示行为的Shape 类型。
  • 不过,这正是发布公告中使用的示例之一。他们应该使用不同的。
【解决方案2】:

此示例使用console.log 来测试推断类型。 console.log 不太关心它的参数类型,所以这两种情况都没有错误。

如果测试需要更具体的类型,结果会有所不同:

// Altered getShapes function
function getShapes() {
  const result = [
    { kind: "circle", radius: 100 },
    { kind: "square", sideLength: 50 },
  ];

  return result;
}

for (const shape of getShapes()) {
  if (shape.kind === "circle") {
    const radius: number = shape.radius;
  } else {
    const length: number = shape.sideLength;
  }
}

开启--strictNullChecks,你会得到两个错误:

t.ts:25:11 - error TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.

25     const radius: number = shape.radius;
             ~~~~~~

t.ts:29:11 - error TS2322: Type 'number | undefined' is not assignable to type 'number'.
  Type 'undefined' is not assignable to type 'number'.

29     const length: number = shape.sideLength;
             ~~~~~~

正如针对此功能所宣传的那样,当使用as const 断言使编译器推断出精确类型时不会出现错误。

作为参考,这里是 getShapes() 的返回类型推断的类型,const 声明:

 ( { kind: string; radius: number; sideLength?: undefined; } 
  |{ kind: string; sideLength: number; radius?: undefined; } ) []

如您所见,kind 被扩展为string,并且数组元素类型是一个联合,其中包含声明了所有属性的元素,在某些联合成员中只有其中一些是可选的 - 这就是您没有错误的原因在控制台日志中,例如 shape.radius - 如果联合成员的类型错误,console.log 会很高兴地记录 undefined

以下是getShapes() 的返回类型与as const 断言推断的类型:

readonly [
   { readonly kind: "circle"; readonly radius: 100; }, 
   { readonly kind: "square"; readonly sideLength: 50; }
]

现在它是只读元组类型,而不是数组,并且每个元组成员都有精确的类型(kind 是正确的文字类型,正如预期的那样)。

【讨论】:

  • 那么,如果const 断言能做更多事情,为什么还要在将来创建对象或数组类型时使用const 声明呢?
  • 不是每个人都需要更多,as const 断言使所有内容都是只读的,因此如果您尝试更改数组中第一个元素的例如radius,则会出现类型错误由getShapes() 返回,与const 声明不同。因此,如果您不喜欢“一切都应该是不可变的”范式,那么在某些情况下,as const 断言可能太多了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-03
  • 2012-12-30
  • 1970-01-01
  • 2013-11-06
  • 2020-01-25
  • 2019-07-25
相关资源
最近更新 更多