TypeScript类型声明书写详解

本文总结一下TypeScript类型声明的书写,很多时候写TypeScript不是问题,写类型就特别纠结,我总结下,我在使用TypeScript中遇到的问题。如果你遇到类型声明不会写的时候,多看看lodash的声明,因为lodash对数据进行各种变形操作,所以你能遇到的,都有参考示例。

基本类型

 // 变量
 const num: number = 1;
 const str: string = 'str';
 const bool: boolean = true;

 const nulls: null = null;
 const undefine: undefined = undefined;
 const symbols: symbol = Symbol('symbal');

 const any: any = 'any types'; // typescript的any类型,相当于什么类型约束都没有

数组

 // 数组: 推荐使用T[]这种写法
 const nums: number[] = [1, 2, 3, 4];

 // 不推荐:Array<T>泛型写法,因为在JSX中不兼容,所以为了统一都使用T[]这种类型
 const strs: Array<string> = ['s', 't', 'r'];

 const dates: Date[] = [new Date(), new Date()];

数组的concat方法,返回类型为never[]问题

 // 数组concat方法的never问题
 // 提示: Type 'string' is not assignable to type 'never'.
 const arrNever: string[] = [].concat(['s']);

 // 主要问题是:[]数组,ts无法根据上下文判断数组内部元素的类型
 // @see https://github.com/Microsoft/TypeScript/issues/10479
 const fixArrNever: string[] = ([] as string[]).concat(['s']);

接口

接口是 TypeScript 的一个核心知识,它能合并众多类型声明至一个类型声明:

而且接口可以用来声明:函数,类,对象等数据类型

interface Name {
 first: string;
 second: string;
}

let username: Name = {
 first: 'John',
 second: 'Doe'
};

any、null、undefined、void类型

// 特殊类型
const any: any = 'any types'; // typescript的any类型,相当于什么类型都没写
let nobody: any = 'nobody, but you';
nobody = 123;

let nulls: number = null;
let bool: boolean = undefined;

// void
function printUsername (name: string): void {
  console.log(name);
}

联合类型

联合类型在option bags模式场景非常实用,使用 **| **来做标记

function options(opts: {
  types?: string;
  tag: string | number;
}): void {

}

交叉类型

最典型的使用场景就是继承和mixin,或者copy等操作

// 交叉类型:如果以后遇到此种类型声明不会写,直接看Object.assign声明写法
function $extend<T, U>(first: T, second: U): T & U {
 return Object.assign(first, second); // 示意而已
}

元组 tuple

元组很少使用

let nameNumber: [string, number];

// Ok
nameNumber = ['Jenny', 221345];

// Error
// nameNumber = ['Jenny', '221345'];

let tuple: [string, number];
nameNumber = ['Jenny', 322134];

const [usernameStr, uselessNum] = nameNumber;

type的作用

ype用来创建新的类型,也可以重命名(别名)已有的类型,建议使用type创建简单类型,无嵌套的或者一层嵌套的类型,其它复杂的类型都应该使用interface, 结合implements ,extends实现。

type StrOrNum = string | number;

// 使用
let sample: StrOrNum;
sample = 123;
sample = '123';

// 会检查类型
sample = true; // Error

实践中遇到的问题

第三方库没有提供声明d.ts文件

如果第三方库没有提供声明文件,第一时间去微软官方的仓库https://github.com/borisyankov/DefinitelyTyped 查找,或者在npmjs.com上搜索@types/依赖的模块名大部分情况都可以找到。

手动添加声明文件

声明文件一般都是统一放置在types文件夹下

// 例子: types/axios.d.ts
declare module 'axios'; // 这里的axios声明为any类型

全局变量

例如一些库直接把在window上添加的全局变量

// globals.d.ts
// 例子:jQuery,现实中jQuery是有.d.ts
declare const jQuery: any;
declare const $: typeof jQuery;

非JavaScript资源

在前端工程中,import很多非js资源,例如:css, html, 图片,vue, 这种ts无法识别的资源时,就需要告诉ts,怎么识别这些导入的资源的类型。

// 看看vue怎么处理的:shims-vue.d.ts
declare module '*.vue' {
 import Vue from 'vue';
 export default Vue;
}

// html
declare module '*.html';
// css
declare module '*.css';

强制类型转换

有时候遇到需要强制类型转换,尤其是对联合类型或者可选属性时。

// 第一种:使用<>括号
const convertArrType: string[] = <Array<string>>[].concat(['s']);

// 第二种:使用as关键字
const fixArrNever: string[] = ([] as string[]).concat(['s']);

建议使用第二种,因为兼容JSX,第一种官方也不推荐了,虽然它是合法的。

可选属性和默认属性

API中提供的参数很多都有默认值,或者属性可选,怎么书写呢?

class Socket {}
// 联合类型
export type SocketType = 'WebSocket' | 'SockJs';

export interface SocketOptions {
 type: SocketType;
 protocols?: string | string[]; // 可选
 pingMessage: string | (() => string); // 联合类型,可以为string或者函数
 pongMessage: string | (() => string);
}

// 默认值
export function eventHandler = (
 evt: CloseEvent | MessageEvent | Event,
 socket: Socket,
 type = 'WebSocket' // 默认值
) => any;

独立函数怎么声明类型

刚开始我也很纠结这个问题,我就是一个独立的函数,怎么声明类型呢?尤其是写事件处理函数的API时。

class Socket {}
// 函数的声明方式
export type SocketEventHandler = (
 evt: CloseEvent | MessageEvent | Event,
 socket: Socket
) => any;

const eventHandler: SocketEventHandler = (evt, socket) => {
}

// 可选参数和rest参数
let baz = (x = 1) => {};
let foo = (x: number, y: number) => {};
let bar = (x?: number, y?: number) => {};
let bas = (...args: number[]) => {};

索引属性类型声明

JavaScript中的对象都可以使用字符串索引直接取属性或者调用方法,TypeScript中也有相应的类型声明方法。

type Hello = {
  hello: 'world';
  // key只是一个形式属性名(类似形参一样)
  [key: string]: string;
};

const greeting: Hello = {
  hi: 'morning'
}

console.log(greeting['hi'])

动态添加的属性声明

有的时候我们只声明了一个基本的类型结构,然后后续有扩展的情况 ,尤其时二次封装时的options。

interface AxiosOptions {}

type AjaxOptions = {
  axiosOptions: AxiosOptions;
  // 额外扩展的放入到单独的属性节点下
  extraOptions: {
    [prop: string]: any
  };
};

type AjaxOptions1 = {
 axiosOptions?: AxiosOptions;
 // 不要这样写,因为axiosOptions拼写错误时,ts不会提示
 // 尽量把后续扩展的属性,移动到独立的属性节点下
 [prop: string]: any
};

const ajaxOptions: AjaxOptions1 = {
 axiosOptions1: {}; // 本意是axiosOptions,但是ts不会提示
}

!的使用

! 标识符告诉ts编译器,声明的变量没有问题,再运行期不会报错。

class BaseSelect extends Vue {
  options: string[]; // 这里会提示没有在constructor中初始化

  created() {
    this.options = ['inited']
  }
}

class BaseSelect extends Vue {
  options!: string[]; // 使用 ! 告诉编译器,我知道自己在做什么

  created() {
    this.options = ['inited']
  }
}

this的使用

对于独立使用的函数,可以声明指定的调用上下文

class Handler {
  info: string;
  // 声明指定的this上下文
  onClickBad(this: Handler, e: Event) {
    // oops, used this here. using this callback would crash at runtime
    this.info = e.message;
  }
}
let h = new Handler();
uiElement.addClickListener(h.onClickBad); // error!

声明合并(扩展Vue声明)

来看看使用场景,扩展vue,在vue上添加全局的属性。

// vue的声明在 vue/types/vue.d.ts

declare module 'vue/types/vue' {
 // 相当于Vue.$eventBus
 interface Vue {
  $eventBus: Vue;
 }

 // 相当于在Vue.prototype.$eventBus
 interface VueConstructor {
  $eventBus: Vue;
 }
}

总结

TypeScript声明还有很多高级的用法,目前我也没有用到那么多,在我纠结不会写声明的时候,我就会看看别人的声明文件时怎么写的。

注意:尽量不要把解构和声明写在一起,可读性极差。

class Node {
 onNodeCheck(checkedKeys: any, { // 解构
   checked, checkedNodes, node, event,
  } : { // 声明
   node: any;
   [key: string]: any;
  }
 ) {
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • TypeScript入门-基本数据类型

    大致介绍 TypeScript是由C#语言之父Anders Hejlsberg主导开发的一门编程语言,TypeScript本质上是向JavaScript语言添加了可选的静态类型和基于类的面向对象编程,它相当于是JavaScript的超集 ES5.ES6和TypeScript的关系: 安装 首先需要安装npm,然后在输入 npm install -g typescript 安装完成后,因为TypeScript是以.ts结尾的,要想运行就得把他编译js文件,编译的方法特别简单就是使用tsc命令 ts

  • TypeScript Type Innference(类型判断)

    TypeScript 是微软开发的 JavaScript 的超集,TypeScript兼容JavaScript,可以载入JavaScript代码然后运行.TypeScript与JavaScript相比进步的地方 包括:加入注释,让编译器理解所支持的对象和函数,编译器会移除注释,不会增加开销:增加一个完整的类结构,使之更新是传统的面向对象语言. 为什么会有 TypeScript? JavaScript 只是一个脚本语言,并非设计用于开发大型 Web 应用,JavaScript 没有提供类和模块的概

  • TypeScript学习之强制类型的转换

    前言 使用强类型变量常常需要从一种类型向另一种类型转换,通常使用ToString或ParseInt可以来实现一些简单的转换,但是有时候需要像.NET语言中那样将一种类型显示的转换为另一种类型,在TypeScript规范中,被称为"类型断言",它仍然是类型转换,只是语法是有些不同.下面来详细看看TypeScript的强制类型转换. TypeScript强制类型转换 在 TypeScript 中将一个 number 转换成 string ,这样做会报错: var a:number = 12

  • TypeScript 学习笔记之基本类型

    在 TypeScript 中一共有 7 种基本类型. 1.boolean 复制代码 代码如下: var isDone: boolean = false; 2.number 代表 JavaScript 中的数字.在 JavaScript 中,无论是"整数"还是"浮点数",都是以双精度浮点类型存储的. 复制代码 代码如下: var height: number = 6; 3.string 代表字符串.跟 JavaScript 一样,可以使用一对双引号(")或一

  • TypeScript类型声明书写详解

    本文总结一下TypeScript类型声明的书写,很多时候写TypeScript不是问题,写类型就特别纠结,我总结下,我在使用TypeScript中遇到的问题.如果你遇到类型声明不会写的时候,多看看lodash的声明,因为lodash对数据进行各种变形操作,所以你能遇到的,都有参考示例. 基本类型 // 变量 const num: number = 1; const str: string = 'str'; const bool: boolean = true; const nulls: null

  • Zod进行TypeScript类型验证使用详解

    目录 引言 什么是类型验证,为什么需要它? 为什么要使用zod? 使用 Zod 进行类型验证的示例 Primitives 对象 类型推断 组合类型 注意事项 安全解析 无法识别的Key被删除 其他事项 Zod 与其他库的比较 结论 引言 这篇文章将描述如何使用Zod为您的项目设置类型验证.Zod 是一个用于类型声明和验证的开源 TypeScript 库.我们将研究为什么使用 Zod 进行类型验证,提供如何使用它的示例,并将其与其他库进行比较. 什么是类型验证,为什么需要它? 类型验证是验证数据结

  • TypeScript的类型指令单行注释详解

    目录 正文 @ts-ignore 和 @ts-expect-error @ts-check 和 @ts-nocheck 正文 单行注释应该在项目里用的很少吧, 我没见过在项目中使用过, 但是了解一下又不吃亏! 那么一起来看看吧!这里开启了TypeScript提示器. 这里谈谈我对它的理解,也可以看看林不渡的TypeScript小册 一般单行注释是以@ts-开头 @ts-ignore 和 @ts-expect-error @ts-ignore 和 @ts-expect-error 仅仅对紧随其后的

  • TypeScript类型断言VS类型守卫示例详解

    目录 类型断言 类型守卫 使用 in 关键字 使用 instanceof 关键字 使用 typeof 关键字 自定义类型守卫 总结 类型断言 类型断言有两种写法,分别为value as Type和<Type>value,它让 TypeScript 编译器将 value 当作 Type 类型.类型断言是一个编译时特性,不进行类型转换,因此不会影响变量在运行时的数据类型.如果某变量是 any 类型,但现在你知道它确切的数据类型,使用类型断言能让 IDE 有代码提示的能力,也能让 TypeScrip

  • TypeScript 基本数据类型实例详解

    目录 TypeScript 介绍 类型分配 类型推导 数组 元组 object null 和 undefined 特殊类型 any unknown never void TypeScript 介绍 TypeScript 是 JavaScript 的超集,提供了 JavaScript 的所有功能,并提供了可选的静态类型.Mixin.类.接口和泛型等特性. TypeScript 的目标是通过其类型系统帮助及早发现错误并提高 JavaScript 开发效率. 通过 TypeScript 编译器或 Ba

  • 基于Python的文件类型和字符串详解

    1. Python的文件类型 1. 源代码--直接由Python解析 vi 1.py #!/usr/bin/python print 'hello world' 这里的1.py就是源代码 执行方式和shell脚本类似: chmod +x 后,./1.py Python 1.py 2. 字节代码 Python源码文件经编译后生成的扩展名为pyc的文件 编译方法: [root@t1 py]# cat 2.py #!/usr/bin/python import py_compile py_compil

  • C#元组类型ValueTuple用法详解

    System.Tuple 类型是在.NET 4.0中引入的,但是有两个明显的缺点:(1) Tuple 类型是引用类型.(2) 没有构造函数支持. 为了解决这些问题,C# 7 引入了新的语言功能以及新的类型. 现在,如果您需要从函数中返回两个值的合并结果,或者把两个值合并到一个哈希表中,可以使用System.ValueTuple类型并使用一个精短的语法来构造它们: // 构建元组实例 var tpl = (1, 2); // 在字典中使用元组 var d = new Dictionary<(int

  • Java中值类型和引用类型详解

    我们都知道java是一种面向对象的编程语言,但是在实际意义上java并不是纯面向对象,因为面向对象的意义就是万物皆对象,那么如果说int类型的变量也是一个对象的话,那么我们应该能用"."这个东西访问到它的属性或者是方法,例如: import java.util.ArrayList; import java.util.List; public class Test { public static void main(String[] args) { List<Integer>

  • Java类和成员变量声明类详解

    目录 声明类 声明成员变量 访问修饰符 类型 变量名 声明类 定义类: class MyClass { // 字段.构造函数和 // 方法声明 } 这是一个类声明.类主体(大括号之间的区域)包含提供从类创建的对象的生命周期的所有代码: 用于初始化新对象的构造函数,提供类及其对象状态的字段的声明,以及方法来实现类及其对象的行为. 前面的类声明是最小的.它仅包含所需的类声明的那些组件.您可以在类声明的开头提供有关该类的更多信息,例如其超类的名称.是否实现任何接口等. 例如: class MyClas

  • JS疑惑的数据类型及类型判断方法详解

    目录 前言 数据类型 类型判断 一.typeof方法 二.Object.prototype.toString.call()方法 小插曲 三.Array.isArray() 四.obj instanceof Object 结语 前言 关于javascript这门语言的数据类型你了解多少呢?你有什么方法能够快速的判断数据类型呢?如果可以那如何实现类型转换呢?带着这三个问题开始我们今天的学习吧 数据类型 在javascript中数据类型我们一般分为基本数据类型(值类型) 和 引用数据类型(对象类型):

随机推荐