Typescript中的as、问号与感叹号详解

1、as关键字表示断言

在Typescript中,表示断言有两种方式。一种是扩号表示法:

let someValue: any = "this is a string";
let strLength: number = (someValue).length;

另一种使用as关键字:

let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;

2、问号(?)用于属性定义

问号表示可选的属性,一般用于属性定义,如,用于接口时:

interface SquareConfig {
    color?: string;
    width?: number;
}
function createSquare(config: SquareConfig) {
    if (config.color) {
        console.log(config);
    }
}

可选属性的含义是:使用这个属性时,要么这个属性名不存在,要么必须符合属性的类型定义

比如上述createSquare函数编译时会报error错误:

error TS2551: Property 'clor' does not exist on type 'SquareConfig'.

如果修改createSquare,将config.color的值改为undefined,会怎样?

interface SquareConfig {
    color?: string;
    width?: number;
}
function createSquare(config: SquareConfig) {
    config.color = undefined;
    if (config.color) {
        console.log(config);
    }
}

这时并没有编译报错!明明config.color定义的是string类型呀?

即便是添加–strictNullChecks进行编译,也不会报错。可见,可选属性所定义的类型,并没有被typescript严格地对待,默认并不检查undefined。需要注意的是,将上述undefined改成null时,普通编译也不报错,–strictNullChecks编译会报如下错误:

error TS2322: Type 'null' is not assignable to type 'string | undefined'

从这句报错中,我们可以得出这样的结论:可选属性等价于一个union类型,union了undefined;不加–strictNullChecks编译时,null可以赋值给undfined类型。也就是说,SquareConfig的定义与下面的代码等价:

interface SquareConfig {
    color: string|undefined;
    width: number|undefined;
}

下面比较一下可选属性与正常属性。再次修改createSquare,将color属性修改为正常属性。

interface SquareConfig {
    color: string;
    width?: number;
}
function createSquare(config: SquareConfig) {
    config.color = undefined;
    if (config.color) {
        console.log(config);
    }
}

以–strictNullChecks编译,报错了:

error TS2322: Type ‘undefined' is not assignable to type ‘string'

这个比较也验证了上述的结论。

问号(?)用于属性读取

问号用于属性读取,主要有两个场景:一是读取数组元素(如下面的node[i]),二是读取不确定的类型如any,union,可选类型(如node[i].data)等。如下例,保存为index.ts:

interface VNodeData {
    class?: string;
}
interface VNode {
    sel?: string;
    data?: VNodeData;
}
function test(node: VNode[]) {
    let i = 0;
    var b = node[i].data.class;
    if(b !== undefined) {
        console.log(1);
    }
}

用tsc --strictNullChecks index.ts,报错:

error TS2532: Object is possibly 'undefined'

下面将一一展示这一行代码var b = node[i].data.class;修改改后的效果。

1、修改为var b = node[i]?.data.class;,然后编译。报错:

Object is possibly 'undefined'

2、修改为var b = node[i]?.data?.class;,然后编译。编译通过,查看编译后的对应代码为:

function test(node) {
    var _a, _b;
    var i = 0;
    var b = (_b = (_a = node[i]) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b["class"];
    // var b = node[i].data.class;//报错
    if (b !== undefined) {
        console.log(1);
    }
}

var b = node[i]?表示,如果node[i]的值为null或者undefined,则b等于undefined,否则b=node[i]。

3、修改为var b = (node[i] as VNode).data?.class;,然后编译。编译通过,查看编译后的对应代码为:

function test(node) {
    var _a;
    var i = 0;
    var b = (_a = node[i].data) === null || _a === void 0 ? void 0 : _a["class"];
    // var b = node[i]?.data?.class;
    // var b = node[i].data.class;//报错
    if (b !== undefined) {
        console.log(1);
    }
}

此时,使用node[i]时,Typescript编译器将不再对其判断是否为null和undefined。即:var b = node[i] as VNode直接会被编成var b = node[i]。

4、修改为var b = node[i]!.data?.class,然后编译。编译通过,查看编译后的对应代码为:

function test(node) {
    var _a;
    var i = 0;
    var b = (_a = node[i].data) === null || _a === void 0 ? void 0 : _a["class"];
    // var b = (node[i] as VNode).data?.class
    // var b = node[i]?.data?.class;
    // var b = node[i].data.class;//报错
    if (b !== undefined) {
        console.log(1);
    }
}

可见,3和4的编译后代码完全一样,!的作用此时与as是等价的。然而,!只是用来判断null和undefined;as则可用于变更(缩小或者放大都可以)类型检测范围,仅当as后面跟的类型是一个非空类型时,两者才等价。如下例中,不能将as用法改为!。

interface Cat {
    action: string;
}
interface Dog {
    action: string;
}
type Animal = Cat | Dog;
let action:Animal = {} as Cat;

结论

1、as和!用于属性的读取,都可以缩小类型检查范围,都做判空用途时是等价的。只是!具体用于告知编译器此值不可能为空值(null和undefined),而as不限于此。

2、?可用于属性的定义和读取,读取时告诉编译器此值可能为空值(null和undefined),需要做判断。

到此这篇关于Typescript中的as、问号与感叹号详解的文章就介绍到这了,更多相关Typescript中as、问号与感叹号内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 详解TypeScript映射类型和更好的字面量类型推断

    概述 TypeScript 2.1 引入了映射类型,这是对类型系统的一个强大的补充.本质上,映射类型允许w咱们通过映射属性类型从现有类型创建新类型.根据咱们指定的规则转换现有类型的每个属性.转换后的属性组成新的类型. 使用映射类型,可以捕获类型系统中类似Object.freeze()等方法的效果.冻结对象后,就不能再添加.更改或删除其中的属性.来看看如何在不使用映射类型的情况下在类型系统中对其进行编码: interface Point { x: number; y: number; } inte

  • TypeScript 中如何限制对象键名的取值范围

    当我们使用 TypeScript 时,我们想利用它提供的类型系统限制代码的方方面面,对象的键值,也不例外. 譬如我们有个对象存储每个年级的人名,类型大概长这样: type Students = Record<string, string[]>; 理所当然地,数据就是长这样: const students: Students = { Freshman: ["David", "John"], sophomore: [], Junior: ["Lil

  • 一文搞懂TypeScript的安装、使用、自动编译的教程

    1. 初识 TypeScript 上篇文章给大家介绍过TypeScript的安装.使用.自动编译的实现  需要的朋友点击查看. TypeScript 的介绍 TypeScript 是一种由微软开发的开源.跨平台的编程语言.它是 JavaScript 的超集,最终会被编译为 JavaScript 代码. 2012 年 10 月,微软发布了首个公开版本的 TypeScript,2013 年 6 月 19 日,在经历了一个预览版之后微软正式发布了正式版 TypeScript TypeScript 的作

  • 为什么TypeScript的Enum会出现问题

    目录 发生了什么呢? 什么时候用 控制枚举的数字 Bit值 控制索引 非数字枚举 结论 TypeScript引入了很多静态编译语言的特性,比如class(现在是JavaScript的一部分了),interface, generics和union types等. 但是今天有一个类型需要着重讨论下,这就是enum. 对于很多的静态语言来说,枚举是一个很非常常见的语言特性.比如,c,c#,java和swift.枚举就是你在代码里可以用的一组常量. 我们用TypeScript来新建一个enum来代表一周

  • 深入理解typescript中的infer关键字的使用

    infer 这个关键字,整理记录一下,避免后面忘记了.有点难以理解呢. infer infer是在 typescript 2.8中新增的关键字. infer 可以在 extends 条件类型的字句中,在真实分支中引用此推断类型变量,推断待推断的类型. 例如:用infer推断函数的返回值类型 type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any; type fn = () => number type

  • 教你使用webpack打包编译TypeScript代码

    TypeScript打包 webpack整合 通常情况下,实际开发中我们都需要使用构建工具对代码进行打包: TS同样也可以结合构建工具一起使用,下边以webpack为例介绍一下如何结合构建工具使用TS: 步骤如下: 初始化项目 进入项目根目录,执行命令 npm init -y,创建package.json文件 下载构建工具 命令如下: npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpac

  • Typescript中的as、问号与感叹号详解

    1.as关键字表示断言 在Typescript中,表示断言有两种方式.一种是扩号表示法: let someValue: any = "this is a string"; let strLength: number = (someValue).length; 另一种使用as关键字: let someValue: any = "this is a string"; let strLength: number = (someValue as string).length

  • TypeScript中extends的正确打开方式详解

    目录 前言 extends第一式:继承 类继承类 接口继承接口 接口继承类 extends第二式:三元表达式条件判断 普通的三元表达式条件判断 情况一:Type1和Type2为同一种类型. 情况二:Type1是Type2的子类型. 情况三: Type2类型兼容类型Type1. 带有泛型的三元表达式条件判断 extends第三式:泛型约束 前言 最近完整地看了一遍TypeScript的官方文档,发现文档中有一些知识点没有专门讲解到,或者是讲解了但却十分难以理解,因此就有了这一系列的文章,我将对没有

  • TypeScript中定义变量方式以及数据类型详解

    目录 TypeScript定义变量 变量声明格式 变量类型推导 JS和TS的数据类型 TS中使用JS的数据类型 number类型 boolean类型 string类型 Array类型 Object类型 Symbol类型 null和undefined类型 TS自身特有的数据类型 any类型 unknown类型 void类型 never类型 tuple类型 总结 TypeScript定义变量 变量声明格式 我在前面强调过,在TypeScript中定义变量需要指定 标识符 的类型. 所以完整的声明格式

  • 关于TypeScript中import JSON的正确姿势详解

    前言 Typescript是微软内部出品的,用actionscript的语法在写js的一门新语言,最近 TypeScript 中毒,想想我一个弱类型出身的人,怎么就喜欢上了类型约束--当然这不是重点,重点可能还是 JS 没有接口,我没法靠 class 语法糖写的非常 OO--下面这篇文章想说的其实是在 ts 中如何正确的 import json 格式. 首先我使用了基本姿势 import * as variable from './fooooooo.json' 结果发现他提示我并没有这个 mod

  • React TypeScript 应用中便捷使用Redux Toolkit方法详解

    目录 前言 背景 Redux-Toolkit 常规使用 优化方案 优化 useDispatch 和 useSelector 优化修改 redux 状态的步骤 总结 前言 本文介绍的主要内容是 Redux-Toolkit 在 React + TypeScript 大型应用中的实践,主要解决的问题是使用 createSlice 的前提下消费 redux 状态仍旧有点繁琐的问题. 阅读本文需要的前置知识:了解 React .Redux-Toolkit .TypeScript 的使用. 关于 Redux

  • JSP 中request与response的用法详解

    JSP 中request与response的用法详解 概要: 在学习这两个对象之前,我们应该已经有了http协议的基本了解了,如果不清楚http协议的可以看我的关于http协议的介绍.因为其实request和response的使用大部分都是对http协议的操作. request对象的介绍 我们先从request对象进行介绍: 我们知道http协议定义了请求服务器的格式: 请求行 请求头 空格 请求体(get请求没有请求体) 好了,这里我们就不详细介绍了,我们只看几个应用就可以了,没什么难度: 应

  • vue-cli中的babel配置文件.babelrc实例详解

    本文介绍vue-cli脚手架工具根目录的babelrc配置文件 介绍 es6特性浏览器还没有全部支持,但是使用es6是大势所趋,所以babel应运而生,用来将es6代码转换成浏览器能够识别的代码 babel有提供专门的命令行工具方便转码,可以自行去了解 vue-cli脚手架的.babelrc文件 { // 此项指明,转码的规则 "presets": [ // env项是借助插件babel-preset-env,下面这个配置说的是babel对es6,es7,es8进行转码,并且设置amd

  • typescript nodejs 依赖注入实现方法代码详解

    依赖注入通常也是我们所说的ioc模式,今天分享的是用typescript语言实现的ioc模式,这边用到的主要组件是 reflect-metadata 这个组件可以获取或者设置元数据信息,它的作用是拿到原数据后进行对象创建类似C#中的反射,先看第一段代码: import "reflect-metadata"; /** * 对象管理器 */ const _partialContainer = new Map<string, any>(); const PARAMTYPES =

  • 使用Typescript开发微信小程序的步骤详解

    Typescript的优势咱不需要赘述太多,有兴趣可以参考(https://www.typescriptlang.org/).今天给大家分享一下如何在微信小程序(或者其他同类小程序)开发中使用Typescript. 这个分两种情况,最简单的做法就是在创建项目时,选择Typescript这个选项,如下图所示.但要注意,这个选项只有在选择"Use no cloud service"才有,而另外一种Mini Program Cloud Base则不支持.这个可能是开发工具还没有跟上吧,希望以

  • java中JDBC增删改查操作详解

    目录 前言 一.增删改操作 1.1 PreparedStatement介绍  1.2 增删改操作   1.3 测试 二.查操作 2.1 通用对不同表进行一条数据查询操作 2.2 通用对不同表进行多条数据查询操作 总结 前言         在上一篇博客我们介绍了JDBC的概念以及连接数据库的五种方式JDBC概述及数据库连接方式(数据库连接方式推荐使用第五种),那么我们既然连接上数据库了,那就要对数据进行操作了,那么这一篇我们就来介绍常规的增删改 查操作.       我们先看一遍步骤:    

随机推荐