ts 学习笔记-基础篇
基础
- 原始数据类型
- 任意值
- 类型推论
- 联合类型
- 接口
- 数组
- 函数
- 类型断言
- 申明文件
- 内置对象
原始数据类型
Javascript 的类型分为两种: 原始数据类型(Primitive data types)和对象类型(Object types)。
原始数据类型包括: 布尔值、数字、字符串、null、undefined、以及ES6中的新类型 Symbol。
布尔值
布尔类型,使用 boolean 定义
let isDone: boolean = false
// or
let createByBoolean: boolean = Boolean(1)
布尔对象, 使用Boolean 构造函数
let createByNewBoolean: Boolean = new Boolean(1)
数字
数字类型, 使用 number 定义
let digital: number = 6
let notANumber: number = NaN
let infinityNumber: number = Infinity
数字对象, 使用Number构造函数
let six: Number = new Number(6)
字符串
字符串类型,使用string定义:
let myName: String = 'Tao' // 这里不用 name 是因为 在ts name 已经被声明过,这里不能使用
// 模板字符串
let sentence: string = `Hello, my name is ${myName}`
字符串对象, 使用String定义
let myName: String = new String('Tao')
console.log(myName)
// 模板字符串
let sentence: String = new String(`Hello, my name is ${myName}`) ;
console.log(sentence)
空值
JavaScript 没有空值(Void)的概念,在 TypeScirpt 中,可以用 void 表示没有任何返回值的函数:
function alertName(): void {
alert('My name is Tao')
}
声明一个 void 类型的变量没有什么用,因为你只能将它赋值为 undefined 和 null:
let unusable: void = undefined
Null 和 Undefined
在 TypeScript 中,可以使用 null 和 undefined 来定义这两个原始数据类型:
let u: undefined = undefined
let n: null = null
undefined类型的变量只能被赋值为 undefined,null 类型的变量只能被赋值为 null。
与 void 的区别是,undefined 和 null 是所有类型的子类型。也就是说 undefined 类型的变量,可以赋值给 number 类型的变量,而 void 类型的变量不能赋值给 number 类型的变量:
let num: number = undefined
let str: string = null
// 这些都是允许的, 不会报错
任意值
- 如果是一个普通类型,在复制过程中改变类型是不背允许的,但如果是 any 类型,则云讯被赋值为任意类型
- 任意值(Any) 用来表示允许赋值为任意类型
- 在任意值上访问任何属性都是允许的,也允许调用任何方法
- 声明一个变量为任意值之后面对它的任何操作,返回的内容的类型都是任意类型
- 变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型
let myFavoriteNumber: any = 'six'
myFavoriteNumber = 7
let anyThing: any = 'hello'
console.log(anyThing.myName)
anyThing.setName('Tao').sayHello()
类型推论
如果没有明确的指定类型, 那么 Typescript 会依照类型推论(Type Inference)的规则推断出一个类型
Typescript 2.1 中,编译器会考虑对 myFavoriteNumber 的最后一次赋值来检查类型。
let myFavoriteNumber = 'six'
// 等价于 let myFavoriteNumber: string = 'six'
联合类型
- 联合类型(Union Types)表示取值可以为多种类型中的一种。
- 联合类型使用 | 分隔每个类型
let myFavoriteNumber: string | number
myFavoriteNumber = 'six'
myFavoriteNumber = 6
这里的 string | number 的含义是, 允许 myFavoriteNumber 的类型是 string 或者 number, 但是不能是其他类型。
当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法。
function getString( someThing: string |number ): string {
// 这里的 函数 getString 中的第二个 : string 代表返回值类型
return someThing.toString()
}
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
接口
Typescript 中的接口是一个非常灵活的概念, 除了可以用于对类的一部分行为进行抽象以外, 也常用于对 「 对象的形状(Shape) 」进行描述。
interface Person {
name: sting,
age: number
}
使用接口类型赋值时, 变量的形状必须和接口保持一致,属性数量和类型保持一致,不允许添加未定义的属性。
可选属性,有时候我们希望不要完全匹配一个形状,那么可以用可选属性。 使用 ?
interface Person {
name: string,
age?: number,
}
let tao: Person = {
name: 'Tao'
}
任意属性,有时候我们希望一个借口允许有任意属性
interface Person {
name: string,
age?: number,
[propName: string]: any, // 使用任意属性后, 将不会对对象的任意属性长度进行限制
}
let tao: Person = {
name: 'Tao',
sex: 'male'
}
注意:一旦定义了任意属性,那么确定属性和可选属性都必须是它的子属性
interface Person {
name: string,
age?: number,
[porpName: string]: string
}
let tao: Person = {
name: 'Tao',
age: 26, // err 25 是number类型, 不是string的子属性
sex: 'male'
}
// 所以通常情况下我们会将 任意属性定位 any(任意值)
只读属性,对象中的一些字段只能在创建的时候被赋值,用 readonly 定义只读属性。
注意: 只读约束存在于第一次给对象赋值的时候, 而不是第一个给只读属性赋值的时候
interface Person {
readonly id: number
}
// 第一次给对象赋值, 激活只读约束
let tao: Person = {
id: 89757, // success
}
tao.id = 9527 // err 这里会抛出异常, 因为此处已经不属于第一个个对象赋值
数组
定义数组有多种定义方式
「 类型 + 方括号 」表示法
let fibonacci: number[] = [1, 1, 2, 3, 5]
// 这里的数组 不允许出现其他类型
fibonacci.push('8') // err
let fibonacci: number[] = [1, '1', 2, 3, 5] //err
使用数组泛型(Generic)Array 来表示数组
let fibonacci: Array<number> = [1, 1, 2, 3, 5]
用接口表示数组
interface NumberArray {
[index: number]: number
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5]
any表示数组中允许出现任意类型
let list: any[] = ['tao', 26, { sex: 'male' }]
类数组(Array-like Object)不是数组类型, 比如
arguments
:事实上常见的类数组都有自己的接口定义,如
IArguments
,NodeList
,HTMLCollection
等:function sum() {
let args: IArguments = arguments
}
函数
函数是 javascript 中的一等公民
函数的定义方式有两种-- 函数申明(Function Declaration)和函数表达式(Function Expression):
函数申明(Function Declaration)
function sum(x: number, y: number): number {
return x + y
}
注意,输入多余的(或者少于要求的)参数,是不被允许的:
函数表达式(Function Expression)
let mySum = function(x: numnber, y: number): number {
return x + y
}
用接口定义函数的形状
我们也可以使用接口的方式来定义一个函数需要符合的形状
interface SearchFunc {
(source: string, subString: string): boolean
}
let mySearch: SearchFunc
mySearch = function(source: string, subString: string): boolean {
return source.search(subString) !=== -1
}
可选参数
之前提到, 输入多余的(或者少于要求的)参数是不被允许的, 那么如何定义可选的参数呢?
这里与接口中的可选属性类似 , 也是使用
?
表示可选参数function buildName(firstName: string, lastName?: string): string {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
需要注意的是 可选参数必须接在必需参数的后面
参数默认值
function buildName(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
此时就不受「可选参数必须接在必需参数后面」的限制了
剩余参数(rest)
function push( array: any[], ...items: any[] ) {
items.forEach( function(item) {
array.push(item)
} )
}
rest 参数只能是最后一个参数
重载
重载允许一个函数接受不同数量或类型的参数时, 作出不同的处理。
比如,我们需要实现一个函数
reverse
,输入数字123
的时候,输出反转的数字321
,输入字符串'hello'
的时候,输出反转的字符串'olleh'
。利用联合类型,我们可以这么实现:
function reverse(x: number | string): number | string {
if(typeof x === 'number') {
return Number( x.toString().split('').reverse().join('') )
} else {
return x.split('').reverse().join('') )
}
}
然而这样有一个缺点,就是不能够精确的表达,输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串。
这时,我们可以使用重载定义多个
reverse
的函数类型:function reverse(x: number): number
function reverse(x: string): string
function reverse(x: number | string): number | string {
if(typeof x === 'number') {
return Number( x.toString().split('').reverse().join('') )
} else {
return x.split('').reverse().join('') )
}
}
上例中,我们重复定义了多次函数
reverse
,前几次都是函数定义,最后一次是函数实现。在编辑器的代码提示中,可以正确的看到前两个提示。注意,TypeScript 会优先从最前面的函数定义开始匹配,所以多个函数定义如果有包含关系,需要优先把精确的定义写在前面。
类型断言
类型断言(Type Assertion)可以用来手动指定一个值的类型。
语法
<类型>值
// or
值 as 类型
在 tsx 语法(React 的 jsx 语法的 ts 版)中必须用后一种。
将一个联合类型的变量指定为一个更加具体的类型
上面说过,当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法:
function getLength(something: string | number): number {
return something.length
}
// 报错 number 中无法访问到 length 这个属性值
而有的时候,我们确实要在还不确定类型的时候就访问其中一个类型的属性或方法,此时我们可以使用类型断言
function getLength(something: string | number): number {
if( (<string>something).length ) {
return (<string>something).length
} else {
return something.toString().lengt
}
}
类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的:
function getBoolean(something: string | number): boolean {
return <boolean>something
}
申明文件
当时用第三方库时,我们需要引用它的声明文件。
申明语句:使用declare关键字来定义类型
如:我们需要使用第三方库Jquery获取一个id是foo的元素, 但在 ts 中, 编译器并不知道 $
或者 jQuery
是什么东西。此时,我们需要使用 declare var
来定义它的类型
declare var jQuery: ( selector: string ) => any
jQuery('#foo')
什么是申明文件
通常我们会把声明语句放到一个单独的文件 (jQuery.d.ts)
中, 这就是声明文件
// jQuery.d.ts
declare var jQuery: ( selector: string ) => any
// src/index.ts
jQuery('#foo')
一般来说,ts 会解析项目中所有的 *.ts
文件,当然也包含以 .d.ts
结尾的文件。所以当我们将 jQuery.d.ts
放到项目中时,其他所有 *.ts
文件就都可以获得 jQuery
的类型定义了。
假如仍然无法解析,那么可以检查下 tsconfig.json
中的 files
、include
和 exclude
配置,确保其包含了 jQuery.d.ts
文件。
三斜线指令
三斜线指令 类似于声明文件中的 import
,它可以用来导入另一个声明文件。与 import
的区别是,当且仅当在以下几个场景下,我们才需要使用三斜线指令替代 import
:
当我们在书写一个全局变量的声明文件时
当我们需要依赖一个全局变量的声明文件时
这些场景听上去很拗口,但实际上很好理解
场景一: 在全局变量的声明文件中,是不允许出现 import
, export
关键字的。
场景二: 当我们需要依赖一个全局变量的声明文件时,由于全局变量不支持通过 import
导入,当然也就必须使用三斜线指令来引入了
// types/node-plugin/index.d.ts
/// <reference types="node" />
export function foo(p: NodeJS.Process): string
// src/index.ts
import { foo } from 'node-plugin';
foo(global.process)
第三方声明文件
jQuery 的声明文件, 其实社区已经帮我做好了,jQuery in DefinitelyTyped。我们可以直接下载下来使用, 在使用时我们并不需要在去进行声明
这里更加推荐的是 使用 @types
来统一管理第三库的声明文件。
以 jQuery 为例, 使用方式如下:
npm i @types/jquery
内置对象
JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。
内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准。
ts 学习笔记-基础篇的更多相关文章
- Python学习笔记基础篇——总览
Python初识与简介[开篇] Python学习笔记——基础篇[第一周]——变量与赋值.用户交互.条件判断.循环控制.数据类型.文本操作 Python学习笔记——基础篇[第二周]——解释器.字符串.列 ...
- Python学习笔记——基础篇【第一周】——变量与赋值、用户交互、条件判断、循环控制、数据类型、文本操作
目录 Python第一周笔记 1.学习Python目的 2.Python简史介绍 3.Python3特性 4.Hello World程序 5.变量与赋值 6.用户交互 7.条件判断与缩进 8.循环控制 ...
- java学习笔记-基础篇
Java基础篇 1—12 常识 13 this关键字 14参数传递 16 继承 17 访问权限 28—31异常 1—12 常识 1.文件夹以列表展示,显示扩展名,在地址栏显示全路径 2.javac编译 ...
- Java学习笔记——基础篇
Tips1:eclipse中会经常用到System.out.println方法,可以先输入syso,然后eclipse就会自动联想出这个语句了!! 学习笔记: *包.权限控制 1.包(package) ...
- iOS开发学习笔记:基础篇
iOS开发需要一台Mac电脑.Xcode以及iOS SDK.因为苹果设备都具有自己封闭的环境,所以iOS程序的开发必须在Mac设备上完成(当然,黑苹果应该也是可以的,但就需要花很多的精力去折腾基础环境 ...
- Python学习笔记——基础篇2【第三周】——计数器、有序字典、元组、单(双)向队列、深浅拷贝、函数、装饰器
目录 1.Python计数器Counter 2.Python有序字典OrderredDict 3.Python默认字典default 4.python可命名元组namedtuple 5.Python双 ...
- Python学习笔记——基础篇【第四周】——迭代器&生成器、装饰器、递归、算法、正则表达式
目录 1.迭代器&生成器 2.装饰器 a.基本装饰器 b.多参数装饰器 3.递归 4.算法基础:二分查找.二维数组转换 5.正则表达式 6.常用模块学习 #作业:计算器开发 a.实现加减成熟及 ...
- Python学习笔记——基础篇【第六周】——面向对象
Python之路,Day6 - 面向对象学习 本节内容: 面向对象编程介绍 为什么要用面向对象进行开发? 面向对象的特性:封装.继承.多态 类.方法. 同时可参考链接: http:// ...
- Python学习笔记基础篇-(1)Python周边
一.系统命令 1.Ctrl+D 退出Python IDLE input方法中输入EOF字符,键入Ctrl+D 2.命令行选项: -d 提供调试输出 -O 生成优化的字节码(.pyo文件) -S 不 ...
随机推荐
- 【贪心】8.29题解-cut
cut 题目描述 出于某些方面的需求,我们要把一块N×M的木板切成一个个1×1的小方块. 对于一块木板,我们只能从某条横线或者某条竖线(要在方格线上),而且这木板是不均匀的,从不同的线切割下去要花不同 ...
- docker-compose 部署 Apollo 自定义环境
Apollo 配置中心是什么: Apollo是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境.不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限.流程治理等特性. ...
- STL----vector注意事项
开vector时要注意内存容易炸 最好的办法就是在开vector之后,对他进行一步操作 vector<int> a; a.resize(n); n就是你要开的数组的大小,此时数组里已经插入 ...
- Java基础篇(JVM)——字节码详解
这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎 ...
- 9、zabbix监控
9.1.监控: 1.初级(凡人): (1)识别监控的对象: (2)理解监控的对象: (3)细分监控对象的指标: (4)确定告警的基准线: 2.预中级(飞仙): (1)工具化和监控分离: (2)监控对象 ...
- js 正则表达式 验证数字或字母
let reg= /^(^[0-9]*$)|(^[A-Za-z]+$)/ /*reg= /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]$/*/ if(!reg.test( ...
- CentOS-安装node_exporter导出机器指标
注:node_exporter导出机器指标配合 Grafana+Prometheus使用,可参考:远程监控服务器指标 创建相关目录 $ mkdir /home/prometheus/ -p $ cd ...
- 前端笔记:Html页面常用元素
Html页面由基本几个元素(标签)组成 html.head.body.foot(很少使用). html是整个页面的父级元素,内部包括head.body.foot子类标签. head是页头,及页面的头部 ...
- HTTP:HTTP请求头和响应头详解
HTTP请求报文 HTTP 请求报文由3部分组成(请求行+请求头+请求体) HTTP请求报文分析 1. 是请求方法,GET和POST是最常见的HTTP方法,初次以外还包括 DELETE.HEAD.O ...
- Mybatis学习(2)以接口的方式编程
前面一章,已经搭建好了eclipse,mybatis,mysql的环境,并且实现了一个简单的查询.请注意,这种方式是用SqlSession实例来直接执行已映射的SQL语句: session.selec ...