前言
Typescript是前端离不开的一项技术了,作为初学者,学习起来又很费劲!官网文档又臭又长,狗都不看!网上教程一上来就是20小时,让人望而生怯!
对于Typescript,我们其实并不需要学的非常深入,简单了解简单使用就好了!因此,一篇节省时间,通俗易懂的教程很重要!
本文就要简单但高效的带你入门ts!
基础类型简介
TypeScript 支持与 JavaScript 几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用。TypeScript 包含的数据类型如下表:
数据类型 | 关键字 | 描述 |
---|---|---|
任意类型 | any | 声明为 any 的变量可以赋予任意类型的值。 |
数字类型 | number | 双精度 64 位浮点值。它可以用来表示整数和分数。let binaryLiteral: number = 0b1010; // 二进制 let octalLiteral: number = 0o744; // 八进制 let decLiteral: number = 6; // 十进制 let hexLiteral: number = 0xf00d; // 十六进制 |
字符串类型 | string | 一个字符系列,使用单引号( ' )或双引号( " )来表示字符串类型。反引号( ` )来定义多行文本和内嵌表达式。let name: string = "Runoob"; let years: number = 5; let words: string = 您好,今年是 ${ name } 发布 ${ years + 1} 周年 ; |
布尔类型 | boolean | 表示逻辑值:true 和 false。let flag: boolean = true; |
数组类型 | 无 | 声明变量为数组。// 在元素类型后面加上[] let arr: number[] = [1, 2]; // 或者使用数组泛型 let arr: Array = [1, 2]; |
元组 | 无 | 元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同。let x: [string, number]; x = ['Runoob', 1]; // 运行正常 x = [1, 'Runoob']; // 报错 console.log(x[0]); // 输出 Runoob |
枚举 | enum | 枚举类型用于定义数值集合。enum Color {Red, Green, Blue}; let c: Color = Color.Blue; console.log(c); // 输出 2 |
void | void | 用于标识方法返回值的类型,表示该方法没有返回值。function hello(): void { alert("Hello Runoob"); } |
null | null | 表示对象值缺失。 |
undefined | undefined | 用于初始化变量为一个未定义的值 |
never | never | never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。 |
注意: TypeScript 和 JavaScript 没有整数类型。
示例:src中创建学习文件夹
01_基础类型.ts
//基础类型
(()=>{
//布尔类型 ------>boolean
//数字类型 ------>number
//字符串类型 ------->string
.....................................
})()
main.ts中引入:
import './01_基础类型'
document.write ('哈哈哈哈。我要开始了')
布尔值
最基本的数据类型就是简单的 true/false 值,在JavaScript 和 TypeScript 里叫做 boolean(其它语言中也一样)。
//基础类型
(()=>{
//布尔类型 ------>boolean
//基本语法
//let 变量名:数据类型 = 值
let flag:boolean = true
console.log(flag)
})()
数字
和 JavaScript 一样,TypeScript 里的所有数字都是浮点数。 这些浮点数的类型是 number。 除了支持十进制和十六进制字面量,TypeScript 还支持 ECMAScript 2015中引入的二进制和八进制字面量。
//基础类型
(()=>{
//数字类型 ------>number
let a1: number = 10 // 十进制
let a2: number = 0b1010 // 二进制
let a3: number = 0o12 // 八进制
let a4: number = 0xa // 十六进制
console.log(a1)
})()
字符串
JavaScript 程序的另一项基本操作是处理网页或服务器端的文本数据。 像其它语言里一样,我们使用 string 表示文本数据类型。 和 JavaScript 一样,可以使用双引号(")或单引号(')表示字符串。
//基础类型
(()=>{
//字符串类型 ------->string
let str1: string = '窗前明月光'
//总结:ts中变量一开始是什么类型,那么后期赋值的时候,只能用这个类型
})()
undefined 和 null
TypeScript 里,undefined 和 null 两者各自有自己的类型分别叫做 undefined 和 null。 它们的本身的类型用处不是很大:
let und:undefined = undefined
let nul:null = null
console.log(undefined)
console.log(null)
默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给 number (其他)类型的变量。
但是,会出现报错,原因在于没有关闭tsc的严格模式。
在tsconfig.json中进行更改
"strict": false,
然后npm run dev 重启服务就可以了。
数组
TypeScript 像 JavaScript 一样可以操作数组元素。
定义数组的两种方式
第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组:
let arr1:number[] = [1,2,3,4]
console.log(arr1)
第二种方式是使用数组泛型,Array<元素类型>:
let arr2:Array<number> = [5,6,7,8]
console.log(arr2)
数组定义的方法汇总
定义联合类型数组
let arr:(number | string)[];
// 这个数组中将来既可以存储数值类型的数据, 也可以存储字符串类型的数据
arr3 = [1, 'b', 2, 'c'];
定义指定对象成员的数组:
interface Arrobj{
name:string,
age:number
}
let arr3:Arrobj[]=[{
name:'jimmy',age:22}]
元组 Tuple
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string 和 number 类型的元组。
let arr3 :[string,number,boolean] = ["1",2,true]
console.log(arr3)
元组类型的可选元素
与函数签名类型,在定义元组类型时,我们也可以通过 ? 号来声明元组类型的可选元素
let optionalTuple: [string, boolean?] = ["Semlinker", true];
let optionalTuple: [string, boolean?] = ["Semlinker"];
元组类型的剩余元素
元组类型里最后一个元素可以是剩余元素,形式为 ...X,这里 X 是数组类型。剩余元素代表元组类型是开放的,可以有零个或多个额外的元素。 例如,[number, ...string[]] 表示带有一个 number 元素和任意数量string 类型元素的元组类型。为了能更好的理解,我们来举个具体的例子:
type RestTupleType = [number, ...string[]];
let restTuple: RestTupleType = [666, "Semlinker", "Kakuqo", "Lolo"];
只读的元组类型
任何元组类型加上 readonly 关键字前缀,以使其成为只读元组。具体的示例如下:
const point: readonly [number, number] = [10, 20];
在使用 readonly 关键字修饰元组类型之后,任何企图修改元组中元素的操作都会抛出异常
枚举
enum 类型是对 JavaScript 标准数据类型的一个补充。 使用枚举类型可以为一组数值赋予友好的名字。
enum Color {
Red,
Green,
Blue
}
// 枚举数值默认从0开始依次递增
// 根据特定的名称得到对应的枚举数值
let myColor: Color = Color.Green // 0
console.log(myColor, Color.Red, Color.Blue)
默认情况下,从 0 开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从 1 开始编号:
enum Color {
Red = 1, Green, Blue}
let c: Color = Color.Green
或者,全部都采用手动赋值:
enum Color {
Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green
枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为 2,但是不确定它映射到 Color 里的哪个名字,我们可以查找相应的名字:
enum Color {
Red = 1, Green, Blue}
let colorName: string = Color[2]
console.log(colorName) // 'Green'
any
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any 类型来标记这些变量:
let notSure: any = 4
notSure = 'maybe a string'
notSure = false // 也可以是个 boolean
在对现有代码进行改写的时候,any 类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。并且当你只知道一部分数据的类型时,any 类型也是有用的。 比如,你有一个数组,它包含了不同的类型的数据:
let list: any[] = [1, true, 'free'] list[1] = 100
void
某种程度上来说,void 类型像是与 any 类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void:
/* 表示没有任何类型, 一般用来说明函数的返回值不能是undefined和null之外的值 */
function fn(): void {
console.log('fn()')
// return undefined
// return null
// return 1 // error
}
声明一个 void 类型的变量没有什么大用,因为你只能为它赋予 undefined 和 null:
let unusable: void = undefined
联合类型
联合类型(Union Types)表示取值可以为多种类型中的一种
需求1: 定义一个一个函数得到一个数字或字符串值的字符串形式值
function toString2(x: number | string) : string {
return x.toString()
}
需求2: 定义一个一个函数得到一个数字或字符串值的长度
function getLength(x: number | string) {
// return x.length // error
if (x.length) { // error
return x.length
} else {
return x.toString().length
}
}
类型断言
通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript 会假设你,程序员,已经进行了必须的检查。
类型断言有两种形式。 其一是“尖括号”语法, 另一个为 as 语法
/*
类型断言(Type Assertion): 可以用来手动指定一个值的类型
语法:
方式一: <类型>值
方式二: 值 as 类型 tsx中只能用这种方式
*/
/* 需求: 定义一个函数得到一个字符串或者数值数据的长度 */
function getLength(x: number | string) {
if ((<string>x).length) {
return (x as string).length
} else {
return x.toString().length
}
}
console.log(getLength('abcd'), getLength(1234))
类型推断
类型推断: TS会在没有明确的指定类型的时候推测出一个类型
有下面2种情况: 1. 定义变量时赋值了, 推断为对应的类型. 2. 定义变量时没有赋值, 推断为any类型
/* 定义变量时赋值了, 推断为对应的类型 */
let b9 = 123 // number
// b9 = 'abc' // error
/* 定义变量时没有赋值, 推断为any类型 */
let b10 // any类型
b10 = 123
b10 = 'abc'
代码融合
//基础类型
(()=>{
//布尔类型 ------>boolean
//基本语法
//let 变量名:数据类型 = 值
let flag:boolean = true
console.log(flag)
//数字类型 ------>number
let a1: number = 10 // 十进制
let a2: number = 0b1010 // 二进制
let a3: number = 0o12 // 八进制
let a4: number = 0xa // 十六进制
console.log(a1)
//字符串类型 ------->string
let str1: string = '窗前明月光'
//总结:ts中变量一开始是什么类型,那么后期赋值的时候,只能用这个类型
let und:undefined = undefined
let nul:null = null
console.log(undefined)
console.log(null)
//undefined和null都可以作为其他类型的子类型,把/undefined和null赋值给其他类型的变量,如:number类型的变量
let num2:number = undefined
console.log('数组类型'+'=====================================')
//数组类型
//数组定义方式一
//语法;let变量名 :数据类型[] = [值1,值2,值3]
let arr1:number[] = [1,2,3,4]
console.log(arr1)
//数组定义方法二:泛型的写法
//语法:let 变量名:Array<数据类型> = [值1,值2,值3]
let arr2:Array<number> = [5,6,7,8]
console.log(arr2)
//注意问题:数组定以后,里面的数据类型必须和定义的时候类型保持一致,否则会报错。
console.log('元组类型'+'=====================================')
//元祖类型
//在定义数组时,类型和数据的个数一开始就已经知道了
let arr3 :[string,number,boolean] = ["1",2,true]
console.log(arr3)
//注意问题:元组类型使用时,数据的类型的位置和数据的个数应该和定义在元组的时候的数据类型及位置应该是一致的。
console.log('枚举类型'+'=====================================')
//enum 类型是对 JavaScript 标准数据类型的一个补充。 使用枚举类型可以为一组数值赋予友好的名字。
enum Color {
Red,
Green,
Blue
}
// 枚举数值默认从0开始依次递增
// 根据特定的名称得到对应的枚举数值
let myColor: Color = Color.Green
console.log(myColor) // 1
//默认情况下,从 0 开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从 1 开始编号:
enum Color2 {
Red = 10, Green, Blue}
let c: Color2 = Color2.Green
console.log(c) // 11
//或者,全部都采用手动赋值:
enum Color3 {
Red = 11111, Green = 22222, Blue = 4444}
let c2: Color3 = Color3.Green
console.log(c2)
//枚举类型提供的一个便利是你可以由枚举的值得到它的名字。
// 例如,我们知道数值为 2,但是不确定它映射到 Color 里的哪个名字,我们可以查找相应的名字:
enum Color4 {
Red = 1, Green, Blue}
let colorName: string = Color4[2]
console.log(colorName) // 'Green'
console.log('any类型'+'=====================================')
//let str :any =100
let notSure: any = 4
notSure = 'maybe a string'
notSure = false // 也可以是个 boolean
console.log('对象类型'+'=====================================')
//object类型
//定义一个函数,参数是对象类型,返回值也是对象类型
function getName(name:Object):Object{
console.log(name)
return{
name:name,
age:24
}
}
getName({
name:'佐助'})
console.log('联合类型及类型断言'+'=====================================')
//联合类型(Union Types)表示取值可以是多种类型中的一种
//需求1:定义一个函数得到一个数字或字符串值得字符串形式值
function getString(str:string | number):string{
return str.toString()
}
console.log(getString(123))
//类型断言:告诉编译器,我知道自己是什么类型,也知道自己在干什么
//语法一:<类型>变量名
//语法二:值 as 类型
//需求2:定义一个函数得到一个数字或字符串值得长度
function getStringL(str:string | number):number{
// return str.toString().length
//如果str本身就是string类型,那么没必要调用tostring方法的
if((<string>str).length){
// return (<string>str).length
return (str as string).length
}else{
return str.toString().length
}
}
console.log(getStringL(123445555555))
console.log('类型推断'+'=====================================')
let txt = 100
})()
never
never类型表示的是那些永不存在的值的类型。
值会永不存在的两种情况:
- 如果一个函数执行时抛出了异常,那么这个函数永远不存在返回值(因为抛出异常会直接中断程序运行,这使得程序运行不到返回值那一步,即具有不可达的终点,也就永不存在返回了);
- 函数中执行无限循环的代码(死循环),使得程序永远无法运行到函数返回值那一步,永不存在返回。
// 异常
function err(msg: string): never {
// OK
throw new Error(msg);
}
// 死循环
function loopForever(): never {
// OK
while (true) {
};
}
never类型同null和undefined一样,也是任何类型的子类型,也可以赋值给任何类型。
但是没有类型是never的子类型或可以赋值给never类型(除了never本身之外),即使any也不可以赋值给never
let ne: never;
let nev: never;
let an: any;
ne = 123; // Error
ne = nev; // OK
ne = an; // Error
ne = (() => {
throw new Error("异常"); })(); // OK
ne = (() => {
while(true) {
} })(); // OK
在 TypeScript 中,可以利用 never 类型的特性来实现全面性检查,具体示例如下:
type Foo = string | number;
function controlFlowAnalysisWithNever(foo: Foo) {
if (typeof foo === "string") {
// 这里 foo 被收窄为 string 类型
} else if (typeof foo === "number") {
// 这里 foo 被收窄为 number 类型
} else {
// foo 在这里是 never
const check: never = foo;
}
}
注意在 else 分支里面,我们把收窄为 never 的 foo 赋值给一个显示声明的 never 变量。如果一切逻辑正确,那么这里应该能够编译通过。但是假如后来有一天你的同事修改了 Foo 的类型:
type Foo = string | number | boolean;
然而他忘记同时修改 controlFlowAnalysisWithNever 方法中的控制流程,这时候 else 分支的 foo 类型会被收窄为 boolean 类型,导致无法赋值给 never 类型,这时就会产生一个编译错误。通过这个方式,我们可以确保controlFlowAnalysisWithNever 方法总是穷尽了 Foo 的所有可能类型。 通过这个示例,我们可以得出一个结论:使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。