admin 管理员组

文章数量: 1184232

Typescript 2.7+ 新特性:确定分配断言!符号的使用

  • 项目场景
  • 问题描述
  • 原因分析
  • 解决方案
  • 源代码

项目场景

在用ts写抽象类的时候在初始化成员变量。


问题描述

原泛型类如下:

 class GenericNumber<T>{
    defaltValue : T
    add: (x: T, y: T) => T  
  }

已经关闭了严格模式。虽然编译器没有报错,但是在浏览器控制台出现了如下问题:

Property ‘defaltValue’ has no initializer and is not definitely assigned in the constructor.
Property ‘add’ has no initializer and is not definitely assigned in the constructor.
属性defaltValue和add没有初始化,并且在构造函数中未明确分配。

其中defaltValue是泛型类中的成员变量,也是泛型类。

看报错信息可以知道我没有对这个变量进行初始化,或者在构造器中对这个属性赋初值。那么问题来了,我这是一个泛型类的属性,我怎么赋值??

那么问题就转向,我如何在声明变量的时候给他一个确定但是目前未知类型的初始化的默认值。


原因分析

经过查阅ts的源文档,我终于找到了问题的解决方案。不是严格模式的原因,是ts2.7+版本都需要对属性进行确定分配断言(Definite Assignment Assertions)
由于我使用的是ts4.0+的版本,查了一下ts的文档,发现在2.7+的版本对类型断言有了更严格的限制。也就是说,在声明一个变量之后必须用!给他进行赋值操作。
原文档链接:
Definite Assignment Assertions
原文:

The definite assignment assertion is a feature that allows a ! to be placed after instance property and variable declarations to relay to TypeScript that a variable is indeed assigned for all intents and purposes, even if TypeScript’s analyses cannot detect so.
确定分配断言是一种允许!放在实例属性和变量声明之后的功能,以便中继到TypeScript,即使TypeScript的分析无法检测到该变量的确是出于所有意图和目的而分配的。

他的意思就是说必须在声明变量的同时对他进行赋初值,即使是默认值,但是不能不赋值。否则就会出现属性没有被初始化的问题。

举个文档上简单的小例子:

  let x: number;
  initialize();
console.log(x + x);
//          ~   ~
// Error! Variable 'x' is used before being assigned.
function initialize() {
  x = 10;
}

但是如果用了确定分配断言,就会给声明但是没有初始化的变量一个默认值。即使没有初始化,也不会报used before being assigned.
初始化:

  let x!: number;
  initialize();
  // No error!
  console.log(x + x);
  function initialize() {
    x = 10;
  }

返回20。

不初始化:

  let x!: number;
  // initialize();
  // No error!
  console.log(x + x);
  // function initialize() {
  //   x = 10;
  // }

返回NaN,不报错。


解决方案

把原来的泛型类的成员用确定分配断言进行初始化

class GenericNumber<T>{
	//属性成员初始化
    defaltValue !: T
    //方法成员初始化
    add!: (x: T, y: T) => T
  }

再使用泛型接口的时候就可以正常使用了。还有一种解决方法,就是把成员变成可选的,也不用初始化。但是由于参数的约束,方法add()在实例化时必须传入两个对应的参数。

  class GenericNumber<T>{
    defaltValue ?: T
    add?: (x: T, y: T) => T
  }

但是由于必须要传入defaultValue,这个方法不太符合需求。

源代码

贴一下出问题的原代码:

//泛型类
(() => {
  //定义一个泛型类
  class GenericNumber<T>{
    defaltValue !: T
    add !: (x: T, y: T) => T
  }
  //实例化类的对象的时候在确定泛型的类型
  const g1: GenericNumber<number> = new GenericNumber<number>()
  //设置属性值
 	//因为已经初始化,这句可以不要。但是必须实例化的时候记得传参哈。
   g1.defaltValue = 100

  g1.add = function (x, y) {
    return x+y
  }
  const g2: GenericNumber<string> = new GenericNumber<string>()
  //设置属性值
   g2.defaltValue = 'dxy'
  
  g2.add = function (x, y) {
    return x+y
  }
  
  console.log(g1.add(10,20))//30
   console.log(g2.add('dxy', 'abc'))//dxyabc
})()

本文标签: 断言 初始化 变量 类中 新特性