布尔值:
let flag:boolean=true/false;
数字:
let num:number=3;
字符串:
let s:string="me"/'me'/`me`;
可以用双引号(" ")或者单引号(' ')表示字符串,同时还可以使用模板字符串(` `)。
模板字符串可以定义单行或者多行,可以通过${expr}这种方式嵌入表达式,推荐这种方式
let name:string=`xx`;
let my:string=`我的名字是${name}`;
console.log(my);
//输出:我的名字是xx
但是这时name报错,错误号:TS2451: Cannot redeclare block-scoped variable 'name',只有短短三句语句,居然就出了个错。想来想去,想到了window,在其他页面打印window,果然window上定义了name属性,的确是重复定义了。知道了原因,就好办了。一个方法是稍微改一下变量名;还有一个方法是将脚本封装到模块(module)内。
数组:
两种定义方式:
- 在元素类型后面接上[]
let arr:number[]=[1,2,3,4];
console.log(arr);
//输出:(4) [1, 2, 3, 4]
- 使用数组泛型Array<元素类型>
let arr1:Array<number>=[1,2,3,4];
console.log(arr1);
//输出:(4) [1, 2, 3, 4]
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
元组:
元组就是一个已知元素数量和类型的数组,且各元素的类型不必相同,但是赋值的类型与定义的类型必须一致。
let arr2:[number,string,number]=[1,'2',3];
console.log(arr2);
//输出:(3) [1, "2", 3]
当访问一个越界的元素,会使用联合类型替代。
arr2[3]='2';
console.log(arr2[3]);
//输出:2
//编译报错:TS2322:Type '2' is not assignable to type undefined
枚举:
枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。
enum Week {Sun,Mon,Tues,Wen,Thur,Fri,Sat}
let index0:Week=Week.Sun;
let sun:string=Week[0];
console.log(index0,sun);
//输出:0 "Sun"
一般情况下,从0开始为元素编号。当然,我们也可以手动的设置数值。由下面代码可以看出,当我们设置为从1开始的时候,后面的项是会累加的
enum Week1 {Sun=1,Mon,Tues,Wen,Thur,Fri,Sat}
console.log(Week1.Sun,Week1.Mon,Week1.Tues);
//输出:1 2 3
当然我们可以手动设置数值,但是一定要慎重,不然就会出现下面的情况哟。
enum Week1 {Sun,Mon,Tues=0,Wen,Thur,Fri,Sat}
console.log(Week1.Sun,Week1.Mon,Week1.Tues);
//输出:0 1 0
let day:string=Week1[0];
console.log(day);
//输出:Tues
枚举项也可以是计算所得项,但是如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错。
enum Week2 {Sun='sun'.length,Mon,Tues,Wen,Thur,Fri,Sat}
//编译报错:TS1061:Enum members must have initializers
/*
* 正确使用方式:
*/
enum Week2 {Sun,Mon,Tues,Wen,Thur,Fri,Sat= "sat".length}
let day1:Week2=Week2.Sat;
let sat:string=Week[6];
console.log(day1,sat);
//输出:3 "Sat"
常数枚举,它会在编译阶段被删除,并且不能包含计算成员
/*
* 常数枚举会在编译阶段被删除,一直不明白啥意思,直到看见js文件
*/
枚举:
enum Week2 {Sun,Mon,Tues,Wen,Thur,Fri,Sat= "sat".length}
//编译后js
var Week2;
(function (Week2) {
Week2[Week2["Sun"] = 0] = "Sun";
Week2[Week2["Mon"] = 1] = "Mon";
Week2[Week2["Tues"] = 2] = "Tues";
Week2[Week2["Wen"] = 3] = "Wen";
Week2[Week2["Thur"] = 4] = "Thur";
Week2[Week2["Fri"] = 5] = "Fri";
Week2[Week2["Sat"] = "sat".length] = "Sat";
})(Week2 || (Week2 = {}));
常数枚举:
const enum Directions {Up,Down,Left,Right}
//编译后js:
//无相关内容
//增加一条语句后:
let directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
//编译后js:
var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */];
//输出:(4) [0, 1, 2, 3]
/*
* 常数枚举,不能包含计算所得项成员
*/
const enum Directions {Up,Down,Left,Right="Right".length}
//编译报错:TS2474 const enum member initializers can only contain literal values and other computed enum values.
Any:
当你不清楚变量是什么类型,或者是来自于动态内容(用户输入或第三方库),总之是当你不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查时可以使用any来标记。总之就是啥类型都可以。
let n:any=undefined;
console.log(n);
//输出:undefined
在对现有代码进行改写的时候,any类型是十分有用的,它允许你在编译时可选择地包含或移除类型检查。Any可以访问任何属性也可以调用任何的方法。它与object的区别是:object类型变量只是允许你给他赋任意值,但是不能够在它上面调用任意的方法。
let num1:any=4;
num1.toFixed(); //通过
let num2:object=2;
num2.toFixed(); //报错:TS2339
console.log(num1,num2);
//输出:4 2
变量如果在声明的时候,未指定其类型,那么它会被识别为任意值类型,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。
Void
某种程度上来说,void类型像是与any类型相反,它表示没有任何类型。 当一个函数没有返回值时,你会见到其返回值类型是 void
function f():void {
alert('aaa');
}
一般来说声明一个void变量没什么用,因为他只可以被赋值为null或者undefined
Null和Undefined
null和undefined是所有类型的子类型
let num:number=undefined;
console.log(num);
//输出:undefined
然而,在指定了--strictNullChecks标记后,null和undefined只能赋值给void和他们自己本身,这能避免很多问题,因此官方鼓励使用这个标记。当你在某处想要传入string或null或undefined时,可以使用联合类型。
Never
表示那些永不存在的值得类型,是任何类型的子类型,也可以赋值给任何类型,但是除了never本身外任何一个类型都不可以给他赋值,any也不可以。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
Object
非原始类型,也就是除了原始类型意外的类型,包括{},[],function
使用object类型,就可以更好的使用object的API,比如create
create({ prop: 0 }); // 通过
create(null); // 通过
create([1,2,3]); //通过
create(function a() {
console.log(a);
}); //通过
create(42);//报错,TS2345: Argument of type '42' is not assignable to parameter of type 'object'.
let sym1 = Symbol();
create(sym1); //报错,TS2345: Argument of type 'symbol' is not assignable to parameter of type 'object'.
create("string"); //报错,TS2345: Argument of type '"string"' is not assignable to parameter of type 'object'.
create(false); //Error:(21, 8) TS2345: Argument of type 'false' is not assignable to parameter of type 'object'.
值得注意的是,在TS3.3.3333版本(我使用的版本)中undefined与null类型一样通过了编译,但在文档中却是不通过的
create(undefined);//通过
Symbols
ES6定义的新的原生类型,通过Symbol构造函数创建的,Symbols是不可改变且唯一的
let sym1=Symbol();
console.log(sym1); //Symbol()
let sym2=Symbol('x');
console.log(sym2);//Symbol(x)
let sym3=Symbol('x');
console.log(sym2==sym3);//false
Symbol也可以被用做对象的key值,但是在TS编译的时候报错了。即使不影响输出,但依然不明白为什么。如果您有答案欢迎下方评论,谢谢。
let sym=Symbol();
let obj={
[sym]:'x'
};
console.log(obj[sym]);
//输出:x
但是,编译obj[sym]报错:TS2538: Type 'symbol' cannot be used as an index type.
Symbol也可以与计算属性的声明相结合,来声明对象的属性和类成员
const computed=Symbol();
class C {
[computed](){
return 'sym';
}
}
let c=new C();
let compute=c[computed]();
console.log(compute);
//输出:sym
内置Symbol,用来表示语言内部的行为。
- Symbol.hasInstance属性,指向一个内部方法。当其他对象使用 instanceof运算符,判断是否为该对象的实例时,会调用这个方法。比如foo instanceof Foo在语言内部,实际调用的是Foo[Symbol.hasInstance](foo)
/*
* 下面代码:MyClass是一个类,new MyClass()会返回一个实例。该实例的Symbol.hasInstance方法,
* 会在进行instanceof运算时自动调用,判断左侧的运算或者表达式是否为Array的实例。
*/
class MyClass {
[Symbol.hasInstance](foo) {
return foo instanceof Array;
}
}
let m:any=new MyClass();
console.log([1,2,3] instanceof m);
// 输出:true
- Symbol.isConcatSpreadable属性等于一个布尔值,表示该对象用于Arrary.prototype.concat()时,是否可以展开。
/*
* 数组的默认行为是可以展开的,属性默认等于undefined,当该属性等于true时,也可以展开。
*/
let arr=['c','d'];
console.log(['a','b'].concat(arr,'e'));
//输出:(5) ["a", "b", "c", "d", "e"]
console.log(arr[Symbol.isConcatSpreadable]);
//输出:undefined
/*
* 当属性为false时:
*/
let arr1=['c','d'];
arr1[Symbol.isConcatSpreadable]=false;
console.log(['a','b'].concat(arr1,'e'));
//输出:(4) ["a", "b", Array(2), "e"]==['a', 'b', ['c','d'], 'e']
// 0: "a"
// 1: "b"
// 2: (2) ["c", "d", Symbol(Symbol.isConcatSpreadable): false]
// 3: "e"
// length: 4
// __proto__: Array(0)
- 类数组默认不展开,他的属性设为true,才可以展开
let obj:any = {length: 2, 0: 'c', 1: 'd'};
console.log(['a', 'b'].concat(obj, 'e'));
//输出: ["a", "b", {…}, "e"]
// 0: "a"
// 1: "b"
// 2: {0: "c", 1: "d", length: 2, Symbol(Symbol.isConcatSpreadable): true}
// 3: "e"
// length: 4
__proto__: Array(0)
obj[Symbol.isConcatSpreadable] = true;
console.log(['a', 'b'].concat(obj, 'e'));
//输出:['a', 'b', 'c', 'd', 'e']
Symbol.iterator
方法,被for-of
语句调用。返回对象的默认迭代器。Symbol.match
方法,被String.prototype.match
调用。正则表达式用来匹配字符串。Symbol.replace
方法,被String.prototype.replace
调用。正则表达式用来替换字符串中匹配的子串。Symbol.search
方法,被String.prototype.search
调用。正则表达式返回被匹配部分在字符串中的索引。Symbol.species
函数值,为一个构造函数。用来创建派生对象。Symbol.split
方法,被String.prototype.split
调用。正则表达式来用分割字符串。Symbol.toPrimitive
方法,被ToPrimitive
抽象操作调用。把对象转换为相应的原始值。Symbol.toStringTag
方法,被内置方法Object.prototype.toString
调用。返回创建对象时默认的字符串描述。Symbol.unscopables
对象,它自己拥有的属性会被with
作用域排除在外。
类型断言
简单地说就是你很确定、肯定以及100%的相信值得类型。类型断言好比其他语言的类型转换。但是不进行特殊的数据检查和解构,只在编译阶段起作用,没有运行时的影响。
两种形式:除了在TS里使用JSX时,只能使用as语法断言,其他情况两者自行选择
尖括号法
let s=<string>"sa";
console.log(s);//输出:sa
as语法
let s="sa" as string;
console.log(s);//输出:sa